一、集合是什么?
Java集合类是一个用来存放对象的容器,它存放于 java.util 包中,其中每一个对象叫元素。
注意:①、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。
集合存放的是多个对象的引用,对象本身还是放在堆内存中。
③、集合可以存放不同类型,不限数量的数据类型。
二、Java 集合框架图
三、集合详解
从上图可以看到Map接口和Collection接口是所有集合框架的父接口,Java常用的集合包括List,Set,以及Map。而List,Set和Map都是接口,其中List接口,Set接口是继承了Collection接口,而Map接口是没有继承Collection接口,因为List和Set集合一般放的单个对象,Map放的是键值对,也就是成对的两个对象,键值对就是可以根据一个键值获得对应的一个值,因为Collection不具备这种特点,所以Map并没有继承Collection。
1.先谈谈接口:Collection
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements),我们看一下Collection接口的使用:
1 //我们这里将 ArrayList集合作为 Collection 的实现类
2 Collection collection = new ArrayList();
3
4 //添加元素
5 collection.add("AA");
6 collection.add("BB");
7 collection.add("CC");
8
9 //检测是否存在某个元素
10 collection.contains("AA");
11
12 //删除指定元素
13 collection.remove("AA");
14
15 //判断是否为空
16 collection.isEmpty();
17
18 //删除所有元素
19 Collection del = new ArrayList();
20 del .add("CC");
21 collection.removeAll(del );
22
23 //利用增强for循环遍历集合
24 for(Object obj : collection){
25 System.out.println(obj);
26 }
27 //利用迭代器 Iterator
28 Iterator iterator = collection.iterator();
29 while(iterator.hasNext()){
30 Object obj = iterator.next();
31 System.out.println(obj);
32 }
代码中谈到了Iterator,就先说一下Iterator
(1)Iterator:迭代器,它可以说是Collection分支集合的顶层接口,它的内部封装了三个方法,用来遍历集合:
next():返回迭代器刚越过的元素的引用,返回值是 Object,需要强制转换成自己需要的类型
hasNext():判断容器内是否还有可供访问的元素
remove():删除迭代器刚越过的元素
1 //构造 List 的迭代器
2 Iterator it = list.iterator();
3 //通过迭代器遍历元素
4 while(it.hasNext()){ //list中是否存在下一个对象
5 Object obj = it.next(); //遍历,并赋值给对象
6 System.out.println(obj);//输出
7 }
下面来说一下Collection接口下面的list接口和set接口
(2)List集合:有序可重复(顺序是按照放入的顺序排列的,可重复指的是可以放入一样的元素)
List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等,现在分别说一下它们的实现:
①ArrayList :List list1 = new ArrayList();
底层:使用数组实现 。
特点:查找效率高,随机访问效率高,增删效率低,非线程安全的。
代码:实现Arrarylist的基本操作。
1 //生成arrayList实例对象
2 List arrayList= new ArrayList();
3
4 //ArrayList的添加:
5 arrayList.add("a"); //在末尾添加元素
6 arrayList.add("b");
7 arrayList.add("c");
8 arrayList.add("d");
9 arrayList.add("e");
10 arrayList.add(2,"f");//在指定位置插入元素
11
12 //ArrayList的删除
13 arrayList.remove(2);//移除下标为2的元素
14
15 //ArrayList的修改
16 arrayList.set(0,"a");//把下标为1的元素修改为元素"a"
17
18 //ArrayList的查询,这里需要遍历ArrayList
19 //普通for语句遍历
20 for(int i=0;i<arrayList.size();i++){
21 System.out.println(list.get(i));
22 }
23
24 //迭代器方式:
25 //构造 List 的迭代器
26 Iterator intertor= list.iterator();
27 while(intertor.hasNext()){
28 Object obj = it.next();
29 System.out.println(obj);
30 }
②LinkedList:List list2 = new LinkedList()
底层:使用双向循环链表实现。
特点:查找效率低,随机访问效率低,增删效率高,非线程安全的
代码:与实现Arrarylist的基本操作基本一致,此处已不再声明。
③Vector:List list3 = new Vector();
底层:底层数据结构是数组。
特点:查询快,增删慢;线程安全,效率低(Vector是线程安全,因为是线程安全的,所以效率上比ArrayList要低)
代码:与实现Arrarylist的基本操作基本一致。
1 List list = new Vector();
2 list.add("A");
3 list.add("B");
4 list.add("C");
5
6 list.remove("A");
7 list.set(0,"修改");
8
9 list.add(2,"新增");
10
11 for(Object obj:list)
12 {
13 System.out.println(obj);
14 }
15
16 Iterator iterator = list.iterator();
17 while(iterator.hasNext()){
18 Object obj = iterator.next();
19 System.out.println(obj);
20 }
④Stack:就是我们常说到的栈
底层:Stack实际上也是通过数组去实现的。
继承:Stack继承于Vector,意味着Vector拥有的属性和功能,Stack都拥有。
方法:empty(),peek(),pop(),push(E object),search(Object o);下面通过实际的例子来描述一下:
1 Stack stack = new Stack();
2 //添加
3 stack.push("A");
4 stack.push("B");
5 stack.push("C");
6 stack.push("D");
7
8 //查找“A”在栈中的位置
9 int pos = stack.search("A");
10 System.out.println("the postion of A is:"+pos);
11
12 // pop栈顶元素,取出栈顶元素,并将该元素从栈中删除
13 stack.pop();
14
15 // peek栈顶元素,取出栈顶元素,不执行删除
16 String val = (String)stack.peek();
17 System.out.println("peek:"+val);
18
19
20 // 遍历并打印出该栈
21 Iterator iterator = stack.iterator();
22 while (iterator.hasNext()){
23 Object obj = iterator.next();
24 System.out.println(obj);
25 }
对于List中的集合的几种特点怎么来记呢?无非底层就是数组和链表两种,可以这样来记:
数组就像身上编了号站成一排的人,要找第10个人很容易,根据人身上的编号很快就能找到。但插入、删除慢,要望某个位置插入或删除一个人时,后面的人身上的编号都要变。当然,加入或删除的人始终末尾的也快。
链表就像手牵着手站成一圈的人,要找第10个人不容易,必须从第一个人一个个数过去。但插入、删除快。插入时只要解开两个人的手,并重新牵上新加进来的人的手就可以。删除一样的道理。
(3)Set集合:无序不可重复
Set接口的实现类主要有:hashSet、treeSet 、linkedHashSet
① hashSet:Set hashSet = new HashSet();
底层:使用哈希表实现
特点:不能保证元素的顺序;不可重复;不是线程安全的;集合元素可以为 NULL;判断重不重复,是通过对象本身的hashCode()方法和equals()方法决定的,下图可以详细理解元素是否重复。
方法:下面通过例子来了解一下
1 Set hashset = new HashSet();
2 //增
3 hashset.add("A");
4 hashset.add("B");
5 hashset.add("C");
6 //删除
7 hashset.remove("A");
8 System.out.println(hashset.contains("A"));
9 //查
10 for(Object obj:hashset)
11 {
12 System.out.println(obj);
13 }
14
15 Iterator iterator = hashset.iterator();
16 while(iterator.hasNext()){
17 Object obj = iterator.next();
18 System.out.println(obj);
19 }
②treeSet :Set treeSet = new TreeSet();
底层:使用红黑树算法,擅长于范围查询
特点:有序;不可重复
实现:
1 TreeSet set = new TreeSet();
2 set.add("aaa");
3 set.add("aaa");
4 set.add("bbb");
5 set.add("eee");
6 set.add("ddd");
7 set.add("ccc");
8 //正序遍历
9 Iterator iterator = set.iterator();
10 while(iterator.hasNext()){
11 Object obj = iterator.next();
12 System.out.println(obj);
13 }
14 //逆序遍历
15 Iterator iterator1 = set.descendingIterator();
16 while(iterator1.hasNext()){
17 Object obj = iterator1.next();
18 System.out.println(obj);
19 }
③linkedHashSet :Set linkedHashSet = new LinkedHashSet()
底层:底层采用 链表 和 哈希表
特点:有序;不可重复
下面我们说一下三个set接口实现类的异同:
相同点:都不允许元素重复,都不是线程安全的类,解决办法:Set set = Collections.synchronizedSet(set 对象)
不同点:
HashSet:不保证元素的添加顺序,底层采用 哈希表算法,查询效率高。判断两个元素是否相等,equals() 方法返回 true,hashCode() 值相等。即要求存入 HashSet 中的元素要覆盖 equals() 方法和 hashCode()方法
LinkedHashSet:HashSet 的子类,底层采用了哈希表算法以及链表算法,既保证了元素的添加顺序,也保证了查询效率。但是整体性能要低于 HashSet
TreeSet:不保证元素的添加顺序,但是会对集合中的元素进行排序。底层采用 红-黑 树算法(树结构比较适合范围查询)