在本系列教程的上一篇文章中,使用画图的方式展示了JDK中集合框架的基础体系结构。对于其中的Collection组来说,其顶级的接口是Iterable接口,估计熟悉设计模式的读者已经明白,此处该接口的引入就是为了实现迭代器模式。
关于什么是设计模式或者具体到什么是迭代器模式,本文不会展开,不了解的朋友,建议另找资料补充。关于设计模式的学习,我觉得必须给大家推荐一本书,名为《HeadFirst 设计模式》,该书以幽默风趣的方式,非常详细和深入地讲解了23种设计模式中的常见设计模式,同时,该书中的实例代码使用的Java语言,让人倍感亲切。
如果由于各种原因导致暂时没有时间或者精力去学习和掌握迭代器模式,对于学习和吸收本文的知识也不会有太大的影响,大家可以先掌握使用方法和逻辑,背后的原理可以日后再补习。首先,我们来看一下JDK中Iterable接口的源码:
public interface Iterable<T> {
Iterator<T> iterator();
}
可以看到整个接口的内容非常简单,只有一个方法,该方法返回一个Iterator(迭代器)。看到这里我们就知道,所有实现了Iterable接口的类中都有一个可以返回迭代器的iterator()方法。
我们继续深入跟踪下去,发现Iterator也是一个接口,无论是否知道迭代器设计模式,背后的原理都是面向对象编程的三大特性(封装、继承、多态)。Iterator是一个非常简单的接口,源码如下:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
源码面前无秘密,可以看到Iterator接口也只有三个方法:hasNext()方法用于判断是否还有下一个元素;next()方法用于获取下一个元素;remove()方法用于移除当前迭代位置处的某个元素。
此处,我必须感叹一下面向对象编程范式之强大和接口功能之灵活。首先,把遍历集合并且访问或者移除集合元素的一套操作使用迭代器Iterator接口包装起来。其次,以Iterable接口统一标识可以产生Iterator接口的集合类型。最后,只需集合类型去实现Iterable接口,并依据自身的特点生成具体的Iterator接口实现类。整个的思想和实现方式就是标准的迭代器模式,非常精妙。
在看完了Iterable接口的设计之后,我们再接着往下走。Iterable接口的直接子类是Collection接口,具体源码如下:
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
}
从Collection接口含有的方法来看,该接口很好地模拟了一个集合的概念。该接口包含的方法不少,都是一些很直观的增加、移除、判断等方法。注意:由于Collection并没有继承Object从而获得equals(Object o)方法和hashCode(),而实际上Collection接口对应的集合概念又应该有这两个方法,所以这里自己引入这两个方法。
我们知道Collection接口的下面具有多种子类型,比如:
1)List
2)Set
3)Queue
虽然他们在表征的数据结构类型和数据的实际存储方式上具有很大的差异性,但他们都具有Collection接口的所有方法,必要时,可以通过向上转型来使用。
?最后,我们来总结一下:Collection组的接口数量和分支数量都比较多,Map组的接口数量较少,且是一条直线分支;Collection组的顶级接口是Iterable,Map组的顶级接口是Map。实际上,整个集合框架的完整体系结构远比这个复杂,但只要我们心中有这两个图,那么无论是吸收集合框架的后期教程还是实际工作中对数据结构的选择,都能做到手到擒来。
本系列文档会在本人的微信公众号发布,欢迎大家扫码关注。