携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
🏀集合概述
❤️首先我们要先明确一下,什么是集合?有什么用?
⭐️数组其实就是一个集合;集合实际上就是一个容器;可以来容纳其它类型的数据。
⭐️为什么说集合在开发中使用较多?
集合是一个容器,是一个载体,可以一次容纳多个对象。在实际开发中;假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。❤️集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。 (集合中存储的是引用)
❤️注意:集合在java中本身是一个容器,是一个对象。集合中任何时候存储的都是“引用” 。
⭐️当然也可以把多个集合放到一个集合里;通俗来讲:我们用一个袋子装苹果,一个袋子装梨子;那么我们就可以找一个大袋子把这两个小袋子装入其中!
❤️在java中每一个不同的集合,底层会对应不同的数据结构。 往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。不同的数据结构,数据存储方式不同:
⭐️例如:数组、二叉树、链表、哈希表...
(1)集合c1中放数据,可能是放到数组上了。
(2)集合c2中放数据,可能是放到二叉树上了。
.....
⭐️使用不同的集合等同于使用了不同的数据结构!⭐️java中已经将数据结构实现了,已经写好了这些常用的集合类,我们只需要掌握怎么用?在什么情况下选择哪一种合适的集合去使用即可。
例如:
(1)new ArrayList(); 创建一个集合对象,底层是数组。
(2)new LinkedList(); 创建一个集合对象,底层是链表。
(3)new TreeSet(); 创建一个集合对象,底层是二叉树。
.....❤️集合在java JDK中哪个包下?
⭐️java.util.*;所有的集合类和集合接口都在java.util包下。❤️在java中集合分为两大类:
⭐️一类是单个方式存储元素:
单个方式存储元素,这一类集合中超级父接口:java.util.Collection;⭐️ 一类是以键值对儿的方式存储元素
以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
❤️Collection集合继承结构图
❤️集合的内容很重要,为了掌握结合,建议大家自己动手画一下常用的的继承UML图
⭐️Collection集合继承结构图
❤️总结
⭐️List集合存储元素的特点:
有序可重复
有序,存进去的顺序和取出来的顺序相同,每个元素有下标
可重复:存进去1,还可以在存储1
(1)ArrayList: 底层是数组,是非线程安全的。
(2)LinkedList: 底层是双向链表。
(3)Vector: 底层也是数组,线程是安全的,效率比较低,使用较少。
⭐️Set(Map)集合存储元素的特点
无序,不可重复
无序,存进去的顺序和取出的顺序不一定相同,另外Set集合元素没有下标
不可重复,存进去1,不能再次储存了
(1)HashSet: 底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了
(2)TreeSet: 底层是TreeMap,放到TreeSet集合中的元素等同于放在TreeMap集合key部分了。
(3)SorteSet (SorteMap) 集合存储元素特点
首先是无序不可重复(因为继承Set集合),但是SoreSet集合中的元素是可以排序的
可排序:可以按照大小顺序排序
(6)HashMap: 底层是哈希表。
(7)HashTable: 底层也是哈希表,只不过线程是安全的,效率较低使用较少。
(8)Prorerties:线程是安全的,并且key和value只能储存字符串String。
(9)TreeMap:底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序。
🏀Collection集合
❤️Collection接口中常用的方法
❤️关于java.util.Collection接口中常用的方法:
⭐Collection集合中能存放什么元素?
(1)没有使用“泛型”之前,Collection中可以存储Object的所有子类型。
(2)使用了“泛型”之后,Collection中只能存储某个具体的类型。
(3)集合中不能直接存储基本数据类型,也不能存 java对象,只能存储java对象的内存地址
⭐Collection中的常用方法
(1)boolean add(Object e) 向集合中添加元素
(2)int size() 获取集合中元素的个数
(3)void clear() 清空集合
(4)boolean contains(Object obj) 判断当前集合中是否包含元素obj
(5)boolean remove(Object obj) 删除集合中的某个元素
(6)boolean isEmpty() 判断该集合中元素的个数是否为0
(7)Object[] toArray() 把集合转换成数组。【了解】
⭐Collection中的常用方法
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest01 {
public static void main(String[] args) {
// 1.创建一个集合对象
// Collection c = new Collection(); //接口是抽象的,无法实例化
//2.多态
Collection c = new ArrayList();
// 测试Collection接口中的常用方法:
// 2.1 boolean add(Object obj) 向结合中添加元素
c.add(100); // 自动装箱,实际上放进去了一个对象的内存地址。Integer x = new Integer(100)
c.add(3.14); // 自动装箱,不能放基本数据类型,只能存储引用
c.add(new Object());
c.add(new Student());
c.add(true); // 自动装箱
// 2.2 int size() 获取集合中元素的个数
System.out.println("集合中元素的个数是:"+c.size()); // 5
// 2.3 void clear() 清空集合
c.clear();
System.out.println("集合中元素的个数是:"+c.size()); // 0
// 再次重新向集合里面添加元素,虽然不是new的,但是有自动装箱机制,实际上存储的也是引用
c.add("hello");
c.add(100);
c.add(3.14);
c.add("蜘蛛侠");
// 2.4 boolean contains(Object obj) p判断结合中是否包含当前对象
System.out.println(c.contains("蜘蛛侠")); // true
// 2.5 boolean remove() 删除集合中某个元素
System.out.println("集合中元素的个数是:"+c.size()); // 4
c.remove(100);
System.out.println("集合中元素的个数是:"+c.size()); // 3
//2.6 boolean isEmpty() 判断该集合中元素的个数是否为0
System.out.println(c.isEmpty()); //集合不为空 false
c.clear();
System.out.println(c.isEmpty()); //集合为空 true
//2.7 Object[] toArray() 把集合转换成数组(了解)
c.add("abc");
c.add("def");
c.add("100");
c.add(3.14);
Object[] obj = c.toArray();
for (int i = 0; i < obj.length; i++) {
System.out.print(obj[i] + " ");
}
}
}
class Student{
}
❤️Collection集合迭代(重要)
⭐Collection结合继承Iterable,里面有iterator方法,调用这个方法返回Iterator对象;Iterator是一个迭代器对象,通过调用里面的方法就可以完成迭代打印!
⭐迭代器对象Iterator中的两个方法:
(1)boolean hashNext()如果仍有元素可以迭代,则返回true
(2)Object next() 返回迭代的下一个元素⭐注意: 以下讲解的遍历方式/迭代方式,是所有Collection集合通用的一种方式。
在Map集合中不能用;在所有的Collection以及子类中使用。
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
//集合迭代(遍历)专题
public class CollectionTest02 {
public static void main(String[] args) {
// 1.创建集合对象
// 后面的集合无所谓,主要是看前面的Collection接口,怎么遍历/迭代。
Collection c = new ArrayList();
//1.1 添加元素
c.add("abc");
c.add("def");
c.add(100);
c.add(new Object());
// 2.对集合Collection进行遍历/迭代
// 2.1 第一步:获取集合对象的迭代器对象Iterator
Iterator it = c.iterator();
// 2.2 通过以上获取的迭代器对象开始迭代/遍历集合
/*
迭代器对象Iterator中的两个方法:
(1)boolean hashNext()如果仍有元素可以迭代,则返回true
(2)Object next() 返回迭代的下一个元素
*/
// 利用迭代器对象Iterator中的方法取出数据
/*boolean hasNext = it.hasNext();
if(hasNext){
//不管当初存进去什么,取出来的统一都是Object
Object obj = it.next();
System.out.println(obj); //取出abc
}*/
// 利用循环都取出来
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
}
}
⭐迭代器执行的原理
根据上面代码的理解,我们一起画出迭代器的执行原理吧!
❤️ArrayList集合和HashSet集合对比
(1)ArrayList集合:有序可重复,怎么放进去就怎么取出来,并且元素是可以重复的!
(2)HashSet集合:无序不可重复;无序:存进去和取出的顺序不一定相同!
不可重复:存储100,不能再存储100!
(3)it.next()取出来的还是Integer类型(存进去是什么类型取出来还是什么类型),打印的时候才会转换成字符串!
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class CollectionTest03 {
public static void main(String[] args) {
//1.创建集合对象
Collection c1 = new ArrayList();
//2.添加元素
c1.add(1); //自动装箱,Integer x = new Integer(1)
c1.add(2);
c1.add(3);
c1.add(4);
c1.add(1);
//3.迭代/遍历集合
Iterator it = c1.iterator();
/* while(it.hasNext()){
System.out.println(it.next());
}*/
// 写成下面这种方式,来证实取出来的是Integer类型
while(it.hasNext()){
Object obj = it.next();
if(obj instanceof Integer){ // 验证实际上取出来的还是Integer类型
System.out.println(obj); // 1 2 3 4 1
}
}
// HashSet集合:无序不可重复
Collection c2 = new HashSet();
// 无序:存进去和取出的顺序不一定相同。
// 不可重复:存储100,不能再存储100;不会报错,只是不会再打印出来,
c2.add(100);
c2.add(200);
c2.add(300);
c2.add(90);
c2.add(400);
c2.add(50);
c2.add(60);
c2.add(100); //这个100不会被打印出来
Iterator it2 = c2.iterator();
while(it2.hasNext()){
System.out.println(it2.next()); //400 50 100 200 90 300 60
}
}
}
❤️contains方法深入理解
(1)boolean contains(Object o),判断集合中是否包含某个对象o,如果包含返回true, 如果不包含返回false。
(2)contains方法是用来判断集合中是否包含某个元素的方法,那么它在底层是怎么判断集合中是否包含某个元素的呢?
⭐实际上contains方法调用了equals方法进行比对;equals方法返回true,就表示包含这个元素。
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
public class CoolectionTest04 {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
// 向集合中存储元素
String s1 = new String("abc");
c.add(s1);
String s2 = new String("def");
c.add(s2);
// 求集合元素的个数
System.out.println("元素的个数:+"+c.size());
// 新建一个String对象
String x = new String("abc");
// c集合是否包含x?结果是true还是false?
// c集合不包含x,但是结果确实true,这是因为contains底层调用了equals方法
// 所以对于自己定义的类型,一定要重写equals方法
System.out.println(c.contains(x)); //true
}
}
⭐内存图
⭐contains方法测试
⭐测试contains方法
结论: 存放在一个集合中的类型,一定要重写equals方法。
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest05 {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
// 创建用户对象
User u1 = new User("jack");
c.add(u1);
User u2 = new User("jack");
// 判断结合中是否包含u2?结果是true还是false?
// 没有重写equals方法之前,比较的是内存地址,结果false
System.out.println(c.contains(u2)); //false
// 重写equals方法之后,比较的是内容
System.out.println(c.contains(u2)); //true
Integer x = new Integer(100);
Integer y = new Integer(100);
c.add(x);
//true,Integer类里面的equals方法默认已经被重写了
System.out.println(c.contains(y));
}
}
// 创建一个类
class User{
private String name;
// 构造方法
public User() {
}
public User(String name) {
this.name = name;
}
// 重写equals方法
public boolean equals(Object o) {
if(o == null || !(o instanceof User)) return false;
if(this == o) return true;
User u = (User)o;
return u.name.equals(this.name);
}
}
❤️remove方法深入理解
⭐存放在一个集合中的类型,调用remov方法,底层也会调用equals()方法,所以也一定要重写equals方法。
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
//remove方法也调用了equals方法
public class CollectionTest06 {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
// 创建字符串对象并加进去
String s1 = new String("hello");
c.add(s1);
// 创建一个新的字符串对象,并移除
// s1.equals(s2) java认为s1和s2是一样的。删除s2就是删除s1。
String s2 = new String("hello");
c.remove(s2);
// 集合元素的个数
System.out.println(c.size()); //0
}
}
❤️集合和迭代器中的remove方法对比
(1)Iterator it = c.iterator();获取迭代器对象,迭代器用来遍历集合,
此时相当于对当前集合的状态拍一个快照,迭代器迭代的时候会参照这个快照进行迭代
(2)关于集合元素的remove,当集合的结构发生改变时,迭代器必须重新获取,如果还是用以前老的迭代器,会出现异常:java.util.ConcurrentModificationException
(3)在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素:
例如:c.remove(o);会出现:java.util.ConcurrentModificationException
(4)在迭代元素的过程当中,一定要使用迭代器Iterator的remove方法,删除元素,
例如:it.remove(),是可以的,因为再删除元素的同时,会把快照里的元素也删除!
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest07 {
public static void main(String[] args) {
//1、 创建集合,正常打印
Collection c = new ArrayList();
// 注意:此时获取的迭代器,指向的是那是集合中没有元素状态下的迭代器。
// 一定要注意:集合结构只要发生改变,迭代器必须重新获取。
// 当集合结构发生了改变,迭代器没有重新获取时,调用next()方法时:java.util.ConcurrentModificationException
//Iterator it = c.iterator();
// 添加元素
c.add(1); // Integer类型
c.add(2);
c.add(3);
// 获取迭代器
Iterator it = c.iterator();
while(it.hasNext()){
// 编写代码时next()方法返回值类型必须是Object。
// Integer i = it.next(); //err
Object obj = it.next();
System.out.println(obj);
}
//2,创建集合,删除集合中的元素
Collection c2 = new ArrayList();
c2.add("abc");
c2.add("def");
c2.add("xyz");
Iterator it2 = c2.iterator();
while(it2.hasNext()){
Object o = it2.next();
// 1.使用集合中的remove方法删除,err
//c2.remove(o); 直接通过集合去删除元素,没有通知迭代器。
//(导致迭代器的快照和原集合状态不同。)
// 删除元素之后,集合的结构发生了变化,应该重新去获取迭代器
// 但是,循环下一次的时候并没有重新获取迭代器,所以会出现异常:java.util.ConcurrentModificationException
// 出异常根本原因是:集合中元素删除了,但是没有更新迭代器(迭代器不知道集合变化了)
// 2.使用迭代器中的remove方法来删除
// 迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中的元素)。
it2.remove(); // 删除的一定是迭代器指向的当前元素。
System.out.println(o);
}
System.out.println(c2.size()); //0,此时迭代器中的元素个数是0
}
}
🥅List集合
测试List接口中常用方法
(1)List集合存储元素特点:有序可重复
有序:List集合中的元素有下标;从0开始,以1递增。
可重复:存储一个1,还可以再存储1。
(2)List既然是Collection接口的子接口,那么List接口肯定有自己 “特有”的方法:
void add(int index, Object element) //1. 在列表指定位置插入指定元素 //这个方法使用不多,因为ArrayList底层是数组,向指定位置插入,效率比较低 Object get(int index) //2.根据下标获取元素 Object set(int index, Object element) //3.根据下标修改元素 Object remove(int index) // 4.通过下标删除指定位置的元素 int indexOf(Object o) //5.获取指定对象第一次出现的索引 int lastIndexOf(Object o) //6.获取指定对象最后一次出现的索引
(3)补充:计算机英语,增删改查这几个单词要知道:
增:add、save、new
删:delete、drop、remove
改:update、set、modify
查:find、get、query、select
package com.bjpowernode.javase.collection;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
public class ListTest01 {
public static void main(String[] args) {
// 创建List类型的集合
List mylist = new ArrayList();
// 添加元素
mylist.add("A"); //默认都是在列表的尾部插入指定元素
mylist.add("B");
mylist.add("C");
mylist.add("D");
mylist.add("C");
// 1.在列表指定位置插入指定元素
mylist.add(1,"K");
//迭代整个集合
Iterator it = mylist.iterator();
while (it.hasNext()) {
System.out.print(it.next()+" "); //A K B C D C
}
System.out.println();
// 2.根据下标获取元素
System.out.println(mylist.get(0)); // A
// 因为有下标,所以List集合有自己特殊的遍历方式
for (int i = 0; i < mylist.size(); i++) {
System.out.print(mylist.get(i)+" "); //A K B C D C
}
System.out.println();
// 3.根据下标修改元素
mylist.set(1,"H");
for (int i = 0; i < mylist.size(); i++) {
System.out.print(mylist.get(i)+" "); //A H B C D C
}
System.out.println();
// 4.获取指定对象第一次出现的索引
System.out.println(mylist.indexOf("C")); //3
// 5.获取指定对象最后一次出现的索引
System.out.println(mylist.lastIndexOf("C")); //5
// 6.通过下标删除指定位置的元素
mylist.remove(0);
System.out.println(mylist.size()); // 5
}
}
ArrayList集合
⭐️ArrayList集合初始化容量及扩容
ArrayList集合底层采用了数组这种数据结构ArrayList集合是非线程安全的。
(1)默认初始化容量10(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10)
(2)集合底层是一个Object[]数组。
(3)构造方法:new ArrayList() 默认容量是10 new ArrayList(20) 自己定义容量的大小
(4)ArrayList集合的扩容:增长到原容量的1.5倍。
ArrayList集合底层是数组,怎么优化?
尽可能少的扩容。因为数组扩容效率比较低,建议在使用ArrayList集合的时候预估计元素的个数,给定一个初始化容量。
(5)数组优点:检索效率比较高。(每个元素占用空间大小相同,内存地址是连续的,知道首元素内存地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高。)
(6)数组缺点:随机增删元素效率比较低。另外数组无法存储大数据量。(很难找到一块非常巨大的连续的内存空间。)
(7)向数组末尾添加元素,效率很高,不受影响。
(8)这么多的集合中,你用哪个集合最多?
答:ArrayList集合是非线程安全的,用的比较多。因为一般都是往末尾添加元素,往数组末尾添加元素,效率不受影响。另外,我们检索/查找某个元素的操作比较多。
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.List;
public class ArrayTest01 {
public static void main(String[] args) {
//1. 默认初始化容量为10
List list = new ArrayList();
// 集合的size()方法是获取当前集合中元素的个数,而不是获取集合的容量
System.out.println(list.size()); //0
//2. 指定初始化容量为20
List list1 = new ArrayList(20);
System.out.println(list1.size()); //0
}
}
⭐️ArrayList集合的一个特殊方法,把HashSet集合转换成ArrayList集合
如果把一个HashSet集合里的元素,通过new ArrayList(HashSet集合),就可以把一个HashSet集合转换成ArrayList集合!
package com.bjpowernode.javase.collection;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
//ArrayList集合的一个特殊方法,参数里面放集合
public class ArrayTest02 {
public static void main(String[] args) {
//1.默认初始化容量是10
List myList = new ArrayList();
//2.指定初始化容量100
List myList2 = new ArrayList(100);
//3.ArrayList参数是一个集合;可以把HashSet集合转换成ArrayList集合
// 3.1创建一个HashSet集合
Collection c = new HashSet();
// 3.2添加元素
c.add(100);
c.add(50);
c.add(200);
c.add(150);
// 3.3通过构造方法可以把HashSet集合转换成ArrayList集合
List myList3 = new ArrayList(c); //50 100 150 200
// 3.4遍历打印
for (int i = 0; i < myList3.size(); i++) {
System.out.print(myList3.get(i)+" ");
}
}
}
LinkedList集合
⭐️单链表数据结构
(1)我们先看一下简单一点的单链表;对于链表数据结构来说:基本的单元是节点Node。
(2)对于单链表来说,任何一个节点Node中都有两个属性:
第一:存储的数据;
第二:下一节点的内存地址;
(3)结构图如下:
编辑
(4)链表的优缺点:
优点: 随机增删元素效率较低(因为增删元素不涉及到大量元素位移)
缺点: 查询效率较低,每一次查找某个元素的时候都需要从头结点开始往下遍历
(5)我们就简单先实现一下链表的一个功能,后期更新数据结构在细讲!
(1)Node节点
package com.bjpowernode.javase.collection.list;
/*
单链表中的节点:节点是单向链表中基本的单元。
每一个节点Node都有两个属性:
一个属性:是存储的数据。
另一个属性:是下一个节点的内存地址。
*/
public class Node {
// 存储的数据
Object data;
// 下一个节点的内存地址
Node next;
//构造方法
public Node(){
}
public Node(Object data, Node next){
this.data = data;
this.next = next;
}
}
(2)实现功能List
package com.bjpowernode.javase.collection.list;
public class List {
Node header; // 头节点,默认是null
int sz; // 存放元素的个数,默认是0
//1、 增加元素
public void add(Object data){
//如果当前没有节点,那么把第一个节点作为头节点
if(header == null){
header = new Node(data,null);
}else{
//头结点存在,找到尾结点
Node lastNode = findLastNOde(header);
//找到以后进行尾插
lastNode.next = new Node(data,null);
}
sz++; //添加元素就sz++
}
//用来找尾结点的方法
private Node findLastNOde(Node node) {
//1.利用递归找
/* if(node.next == null){
//如果一个节点的next是null,说明这个节点就是末尾节点
return node;
}
return findLastNOde(node.next);
*/
//2.常规方法查找
Node cur = node;
while(cur.next != null){
cur = cur.next;
}
return cur;
}
//2、遍历打印当前元素
public void print(){
Node cur = header;
while(cur != null){
System.out.println(cur.data);
cur = cur.next;
}
}
}
(3)测试
package com.bjpowernode.javase.collection.list;
public class Test {
public static void main(String[] args) {
//1、增加元素
List myList = new List();
myList.add(100);
myList.add(50);
myList.add(200);
//2、当前元素的个数
System.out.println(myList.sz);
//3、遍历打印当前元素
myList.print();
}
}
⭐️链表优缺点
(1)链表的优点:
由于链表上的元素在空间存储上内存地址不连续。
所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。
在以后的开发中,如果遇到随机增删集合中元素的业务比较多时,建议使用LinkedList。(2)链表的缺点:
不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率较低。(3)对比:
ArrayList:把检索发挥到极致。(末尾添加元素效率还是很高的)
LinkedList:把随机增删发挥到极致。( LinkedList也是有下标的)
加元素都是往末尾添加,所以ArrayList用的比LinkedList多。(4)注意: ArrayList之所以检索效率比较高,不是单纯因为下标的原因。是因为底层数组发挥的作用。LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头节点开始一个一个遍历!
package com.bjpowernode.javase.collection;
import java.util.LinkedList;
import java.util.List;
public class LinkedListTest01 {
public static void main(String[] args) {
// LinkedList集合底层也是有下标的。
List list = new LinkedList();
list.add("a");
list.add("b");
list.add("c");
// 通过下标的方式打印LinkedList集合,证明LinkedList集合是有下标的
for(int i = 0; i <list.size(); i++){
Object obj = list.get(i);
System.out.println(obj);
}
}
}
⭐️LinkedList详解(双链表)
(1)LinkedList集合是双向链表。
(2)对于链表数据结构来说,随机增删效率较高。检索效率较低。
(3)链表中的元素在空间存储上,内存地址不连续。有了前面单链表的学习,对于双链表我们就很容易理解了;我们先看一下结构图:
编辑
(1) LinkedList集合没有初始化容量!
(2)最初这个链表中没有任何元素。first和last引用都是null。
(3)不管是LinkedList还是ArrayList,以后写代码时不需要关心具体是哪个集合;因为我们要面向接口编程,调用的方法都是接口中的方法。
package com.bjpowernode.javase.collection;
import java.util.LinkedList;
import java.util.List;
public class LinkedListTest01 {
public static void main(String[] args) {
// 面向接口编程,调用的方法都是接口中的方法。
//想从数组的存储方式改到链表的存储方式,不需要改其它代码,扩展性很强
//List list2 = new ArrayList(); // 这样写表示底层你用了数组。
List list2 = new LinkedList(); // 这样写表示底层你用了双向链表。
// 以下这些方法你面向的都是接口编程。
list2.add("123");
list2.add("456");
list2.add("789");
for(int i = 0; i < list2.size(); i++){
System.out.println(list2.get(i));
}
}
}
Vector集合
1、底层也是一个数组。
2、初始化容量:10
3、Vector集合扩容特点:扩容之后是原容量的2倍。
4、ArrayList集合扩容特点:扩容是原容量1.5倍。
5、Vector中所有的方法都是线程同步的,都带有synchronized关键字,是线程安全的。效率比较低,使用较少。
6、怎么将一个线程不安全的ArrayList集合转换成线程安全的呢?
通过使用集合工具类:java.util.Collections;通过Collections.synchronizedList(集合);就可以把线程不安全变为线程安全啦!
java.util.Collection 是集合接口。
java.util.Collections 是集合工具类。
package com.bjpowernode.javase.collection;
import java.util.*;
public class VectorTest01 {
public static void main(String[] args) {
// 创建一个Vector集合
Vector vector = new Vector();
// 添加元素
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
vector.add(6);
vector.add(7);
vector.add(8);
vector.add(9);
vector.add(10);
// 满了之后扩容(扩容之后的容量是20.)
vector.add(11);
//遍历打印
Iterator it = vector.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
//从非线程安全变为线程安全
List myList = new ArrayList(); //非线程安全的
//变成线程安全的
Collections.synchronizedList(myList);
// myList集合就是线程安全的了。
myList.add("111");
myList.add("222");
myList.add("333");
}
}
🥅Set集合
对于Set集合里的接口和类,实际上是和Map集合一一对应的!我们这里只演示一下简单的使用,后期在讲Map集合在细讲!
HashSet集合
(1)实际上HashSet集合在new的时候,底层实际上new了一个HashMap集合
(2)放到HashSet集合中的元素实际上是放到HashMap集合的key部分了
(3)HashSet集合特点:无序不可重复
(4)HashSet集合初始化容量是16;初始化容量建议是2的倍数
(5)扩容:扩容之后是原容量的2倍
package com.bjpowernode.javase.collection;
import java.util.Set;
public class HashSet {
public static void main(String[] args) {
Set<String> strs = new java.util.HashSet<>();
//添加元素
strs.add("hello3");
strs.add("hello4");
strs.add("hello1");
strs.add("hello2");
strs.add("hello3");
strs.add("hello3");
strs.add("hello3");
strs.add("hello3");
//遍历
for(String s:strs){
System.out.println(s);
}
}
}
/*
hello1
hello4
hello2
hello3
1、存储时顺序和取出的顺序不同。
2、不可重复。
3、放到HashSet集合中的元素实际上是放到HashMap集合的key部分了。
*/
SortedSet集合
(1)TreeSet集合底层实际上是TreeMap;new TreeSet集合的时候,底层实际上new了一个TreeMap集合。
(2)往TreeSet集合中放数据的时候,实际上是将数据放到TreeMap集合中了;TreeMap集合底层采用了二叉树数据结构。(3)TreeSet集合存储元素特点:
无序不可重复的,但是存储的元素可以自动按照大小顺序排序!称为:可排序集合。
无序:这里的无序指的是存进去的顺序和取出来的顺序不同。并且没有下标。
package com.bjpowernode.javase.collection;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest01 {
public static void main(String[] args) {
Set<String> strs = new TreeSet<>();
// 添加元素
strs.add("A");
strs.add("B");
strs.add("Z");
strs.add("Y");
strs.add("Z");
strs.add("K");
strs.add("M");
// 遍历
for(String s:strs){
System.out.println(s);
}
}
}
/*
A
B
K
M
Y
Z
从小到大自动排序!
*/