一、Collection 接口概述
List 的特点是 元素有序、元素可重复。主要实现类有 java.util.ArrayList 和 java.util.LinkedList。
Set 的特点是 元素无序、而且不可重复。主要实现类有 java.util.HashSet 和 java.util.TreeSet。
Collection 接口的方法描述如下:
注意:这里是以JDK8版本来进行学习的。
二、常用方法
1、常用方法
add(Object e):将元素e添加到集合collection中
addAll(Collection coll):将coll集合中的元素添加到当前的集合中
size():获取有效元素的个数
clear():清空集合元素
isEmpty():判断当前集合是否为空
是否包含某个元素:通过元素的equals方法来判断比较
contains(Object obj):判断当前集合中是否包含obj
containsAll(Collection coll):判断形参coll中的所有元素是否都存在于当前集合中
boolean remove(Object obj) : 通过元素的equals方法判断是否是要删除的那个元素。 只会删除找到的第一个元素
removeAll(Collection coll):差集:从当前集合中移除coll中所有的元素
boolean retainAll(Collection c): 把交集的结果存在当前集合中,不影响c
equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同
hashCode():返回当前集合对象的哈希值,返回该集合的哈希值,注意重写 equals 方法时必须要重写该方法,以满足 Object.hashCode 方法的规定;
Object[] toArray():转成对象数组
<T> T[] toArray(T[] a) 根据指定类型转成数组,可以指定数组的类型
iterator(): 返回迭代器对象,用于集合遍历
注意:向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().
2、JDK8新增方法
removeIf(Predicate<? super E>):从该集合中移除满足指定条件的元素,其中 Predicate 是 JDK1.8引入的函数式操作,即传入的参数是一个方法
spliterator():可分割迭代器,用于并行遍历集合中的元素(iterator()方法是顺序遍历)
stream()¶llelStream()JDK1.8引入的流(Stream)式数据处理,分别表示串行流和并行流
forEach(consumer<? super T>)这是继承自 Iterable 接口的方法,该方法也是 JDK1.8引入的,提供遍历集合元素的函数式操作
三、Collection接口及子接口
其中,红色的为 接口,其他的为具体的实现类。
1、Collection接口
2、List 子接口
List 是一个顺序存放的容器,他会保存元素的插入顺序,当然元素也可以通过下标位置直接插入和删除。List容器同时允许重复的元素插入和多个null元素。List提供了一个特殊的iterator,叫做ListIterator,这个接口在下文中也有所描述,可以进行双向遍历元素。
3、Set子接口
Set集合最大的特点是元素不能重复,所有元素都是唯一的存在。Set集合不保证维护元素的顺序。
4、Queue 子接口
四、Collection 集合的遍历
1、通过 toArray() 方法
通过 Collection 的 toArray() 方法,先返回数组,然后遍历数组。
2、Iterator 迭代器遍历
3、foreach 遍历(增强 for)
Java 5时Collection接口继承了java.lang.Iterable接口,因此Collection系列的集合就可以直接使用foreach循环遍历。
增强 for 循环(for each循环)是JDK 1.5 以后出来的一个高级 for 循环,专门用来遍历数组和集合的。
它的内部原理其实是个 Iterator 迭代器,所有在遍历的过程中,不能对集合中的元素进行增删操作。
语法格式:
for(元素的数据类型 迭代变量 : Collection集合or数组){
//写操作代码
}
注意:它用于遍历 Collection 和数组,通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。
Demo:
1 public class Demo{
2 public static void main(String[] args) {
3 int[] arr = {3,5,6,87};
4 //使用增强for遍历数组
5 for(int a : arr){//a代表数组中的每个元素
6 System.out.println(a);
7 }
8 }
9 }
五、思考
1、当自己创建一个动态数组类或容器,可以使用 foreach 遍历吗?
foreach 底层是使用了 Iterator 迭代器。所以需要把当前类实现 Iterable 接口,然后实现iterator() 方法。
Iterator 也是一个接口,它的实现类,通常在集合(容器) 类中使用内部类实现,并在 iterator() 方法中创建它的对象。
Demo:
1 public class MyArrayList implements Iterable{ 2 //实现迭代器 3 @Override 4 public Iterator iterator() { 5 return new MyItr(); 6 } 7 // 私有化的内部类 8 private class MyItr implements Iterator{ 9 private int cursor;//游标 10 11 @Override 12 public boolean hasNext() { 13 System.out.println("还有下一个"); 14 return cursor!=total; 15 } 16 17 @Override 18 public Object next() { 19 System.out.println("拿到下一个"); 20 return data[cursor++]; 21 } 22 23 } 24 }
2、如果遍历数组,什么情况下选用foreach,什么情况下选用for循环?
① 当如果操作中涉及到 【下标】操作时,用for最好
② 当只是查看使用元素的内容,那么选 foreach 更简洁一些
3、如果遍历Collection系列集合,什么情况下选用foreach,是否能选用 for 循环?
首先考虑使用foreach,如果该集合也有索引信息的话,也可以通过for来操作,如果没有下标的信息,就不要用for。即,如果该集合的物理结构是数组的,那么可以用for,如果物理结构是链式,那么使用下标操作效率很低。
4、如果遍历Collection系列集合,什么情况下选用foreach,什么情况下使用Iterator?
① 如果只是查看集合的元素,使用foreach,代码会更简洁。
② 但是如果要涉及到在遍历集合的同时根据某种条件要删除元素等操作,那么选用Iterator。
六、总结
对容器的顶层接口Collection及其子接口做了介绍,在这个接口的规范下,衍生出了非常多的子类,这些子类都风格迥异,各有千秋。但总体来说就是为了满足对容器内部元素的不同操作,无非就是快速存储,读取遍历,排序等等。