Collection容器家族(Iterable接口、Collection接口、List接口、Set接口)
一、什么是接口?
接口中定义的是该继承体系中的扩展功能。
举个例子:(猫狗案例)
狗一般就是看门,猫一般就是作为宠物了。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。
二、Iterable接口
1.在collection集合体系中位置及作用
处于顶层 ,作为最基础的接口。
实现此接口,可以通过iterator迭代器遍历整个集合。
2.Iterable接口中的方法
Iterator<T> iterator(); // 返回一个在一组 T 类型的元素上进行迭代的迭代器。
Iterable只是返回了Iterator接口的一个实例,为什么不把两个接口合二为一,直接在Iterable里面定义hasNext(),next()等方法。是因为实现了Iterable的类可以在实现多个Iterator内部类,例如LinkedList中的ListItr和DescendingIterator两个内部类,就分别实现了双向遍历和逆序遍历。通过返回不同的Iterator实现不同的遍历方式,这样更加灵活。如果把两个接口合并,就没法返回不同的Iterator实现类了。
JDK1.8中新加了两个方法:
default void forEach(Consumer<? super T> action); // 对集合使用foreach()遍历。
forEach()的使用方法(如图):
/**
* 使用forEach()遍历集合
*
* @param list 要遍历的集合
*/
public static void printList(List<Integer> list) {
/**
* num可以任意指定,在只作为变量存储遍历出来的元素(单个元素)
*/
list.forEach(num -> System.out.println(num));
}
default Spliterator<T> spliterator(); // //并行迭代器
Spliterator是一个可分割迭代器(splitable iterator),可以和iterator顺序遍历迭代器一起看。可以通过 tryAdvance() 方法逐个遍历,也可以按照 forEachRemaining() 方法进行按 bulk 逐块的遍历。(内部调用的还是tryAdvance)。使用tryAdvance()方法遍历时内部同时做了 hasNext() 以及 next() 的工作。Spliterator中常用的方法有:tryAdvance()、forEachRemaining()、trySplit()等。
三、Collection接口
1.在Collection集合体系中的位置及作用
出去Iterable接口,它是集合体系中的最底层接口,所有其实现类,子接口都必须实现或继承它的方法。同时改接口规范了不管是线性表(数组和链表)、队列、Hash和树结构集合子类所要实现的共性方法。所有其实现类,在此约束和接口进行实现。
2.Collection的功能概述
添加功能
boolean add(Object obj):添加一个元素
boolean addAll(Collection c):添加一个集合的元素
删除功能
void clear():移除所有元素
boolean remove(Object o):移除一个元素
boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)
判断功能
boolean contains(Object o):判断集合中是否包含指定的元素
boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)
boolean isEmpty():判断集合是否为空
获取功能
Iterator<E> iterator()(重点)
长度功能
int size():元素的个数
面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?
交集功能
boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
把集合转换为数组(更多https://blog.csdn.net/IdealSpring/article/details/81475811)
Object[] toArray()
<T> T[] toArray(T[] a)
以上是Collection中最基本的方法,JDK1.8之后新引入方法:
default boolean removeIf(Predicate<? super E> filter) //删除满足给定条件的集合的所有元素
Collection<Integer> c = new ArrayList<>();
c.add(1);
c.add(2);
c.add(3);
c.add(4);
c.add(5);
/**
* removeIf(Predicate<? super E> filter)的Predicate类型参数属于函数式接口(在类上明确标注了@FunctionalInterface)
* 传入的 x -> x % 2 == 0 是Lambda表达式创建的(过滤掉余数为0的)。
* 其实质是Predicate接口的匿名内部类
*/
c.removeIf(x -> x % 2 == 0);
System.out.println(c);
default Spliterator<E> spliterator() //并行迭代器 ---这个方法是继承自Iterable接口,使用见上文。
default Stream<E> stream() //返回该流的对象(见:https://blog.csdn.net/IdealSpring/article/details/81773750)
default Stream<E> parallelStream() //并行流,我们可以很容易的对数据进行并行操作
Spliterator是一个可分割迭代器(splitable iterator,见名知意了吧)。jdk1.8发布后,对于并行处理的能力大大增强,Spliterator就是为了并行遍历元素而设计的一个迭代器,jdk1.8中的集合框架中的数据结构都默认实现了spliterator。
Stream是元素的集合,这点让Stream看起来用些类似Iterator;可以支持顺序和并行的对原Stream进行汇聚的操作;我们这里不详细的介绍Stream流的具体含义以及使用方式和使用它的好处,大家就暂且把它当作一个高效的Iterator好了,我们把对集合的操作变成了对流的操作。
四、List接口
在Collection集合体系中的位置及作用
Collection集合家族体系中共有量大分支,List和Set。List是基于线性表结构的分支。List接口继承了Collection接口,除了拥有父接口的功能外,额外还扩展了自己的一些方法。
List集合的特有功能:
A:添加功能
void add(int index,Object element):在指定位置添加元素
void add(int index, Collection<? extends E> c):在index位置添加指定集合中所有元素
B:获取功能
Object get(int index):获取指定位置的元素
int indexOf(Object o):元素第一个出现的位置
int lastIndexOf(Object o):元素最后一次出现的位置
C:列表迭代器
ListIterator listIterator():List集合特有的迭代器
ListIterator<E> listIterator(int index):从固定位置开始返回一个listiterator
List<E> subList(int fromIndex, int toIndex):返回一个当前集合的视图 从fromindex开始toindex结束
D:删除功能
Object remove(int index):根据索引删除元素,返回被删除的元素
E:修改功能
Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
JDK1.8中新添加的功能:
default Spliterator<E> spliterator() //1.8新增并行遍历迭代器
default void replaceAll(UnaryOperator<E> operator) //1.8新增替换方法
default void sort(Comparator<? super E> c) //1.8新增排序方法内部实现Arrays.sort(a, (Comparator) c)
List接口规范了基于线性表存储结构的集合,线性表具体划分又可以分成数组和链表,List的子类ArrayList是基于数组结构实现的集合、LinkedList是基于链表结构的实现类集合。还有一个Vector集合,由于底层数据结构是数组,查询快,增删慢。线程安全,效率低等特点,我们在实际开发中基本很少会使用。
五、Set接口
在Collection体系中的位置
set接口和list接口一样,继承了Collection接口。其中拥有collection接口中的方法之外,并没有扩展其他的方法。其主要实现类有HashSet和TreeSet,在HashSet的基础上又延伸出了LinkedHashSet,面试中可能会问到的问题也就只有HashSet和TreeSet各自的实现方式,是否有序,LinkedHashSet和HashSet之间有什么区别,扩展出了什么有什么优势等。
总之Collection这一大规范下划分出了两个小规范,一个是线性表规范,另一个是Set的规范,各自有各自体系的用途,对于我们日后从事优化,开发软件,设计框架等一系列操作时,在选择数据结构,也就是选择容器的使用时必须考虑我到底该用什么,用哪个好一些,考虑是时间效率重要还是空间效率重要等一系列延伸出来的问题。