在阅读正文之前几点说明:
1.此篇博客献给那些初学JAVA的初级程序员,大牛可以忽略(能指点一番更好)
2.此篇博客灵感来自于 看Java核心卷之集合迭代器时,接口对象指向.Iterator()而产生的对Iterator()这个迭代器究竟返回什么对象以及迭代器实现的好奇
3.此篇博客从3条继承线完整讲述了如何设计出了ArrayList
4.此篇博客从源码分析,带你找一点接口程序设计,动态绑定(设计)运用的感觉
一.ArrayList 构成之三条继承线。
ArrayList的使用可以分为2个部分,1个是通过迭代器对数组进行操作,另1个是直接对数组进行操作(利用其中的方法);
于是自然而然分为2个部分(超级接口Iterable和迭代器接口Iterator来进行继承了
而完整构成迭代器 居然涉及了2条线!
①Iterable接口—>Collection接口—>AbstractCollection抽象类—>AbstractList抽象类——>ArrayList
这一条构成了ArraylList的直接操作集
②Collection接口->List接口->AbstractList抽象类(不是AbCollection)
③Itertor接口—>ListIerator接口 —>AbstactList抽象类的内部类(后面重点解释)
二.ArrayList操作集的形成
1.由超级接口Iterable开始,这个接口中只包含一个方法 Iterator iterator();
紧接着往下Colletion接口继承了这个接口,我们看看java.util.Collection可以了解到这里定义了一系列的抽象方法(没有提供default默认实现) 我们先记录其中重要的方法声明
int size();
boolean isEmpty();
boolean contains(Object o);
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);
boolean equals(Object o);
int hashCode();
Iterator<E> iterator(); [从上层继承过来,仍然未实现,可以不显式写出来,我估计写出来放这里 是为了当时设计和读者好阅读]
2.从Collection 往后,AbstractCollection抽象类继承了这个接口。并为其中的许多方法提供了实现,这将以最大限度地减少了实现此接口所需的工作!!
我们具体来看几个这个类所实现的Collection接口方法
public boolean isEmpty() {
return size() == 0;
}
public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))
return true;
}
return false;
}
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
等等还有一些;需要注意到的事情是,这些方法实现的使用的是仍然没有具体实现的方法来实现的!!以public boolean isEmpty() {
return size() == 0;
}为例, 我们可以看到 方法内部就是 size()返回的int值如果是0的话,说明是空的,而此刻size()方法并未有具体实现。
那么为什么这样做呢
子类在之后实现了size(), 如果后面没有对isEmpty进行重写。那么子类A(假设有个A的实例 引用为a)使用a.isEmpty()将调用这里的实现,然后会调用this.size方法,而这里的方法未实现(这里的上一层可能实现了),没关系,虚拟机会找到他应该调用的size()方法的[动态绑定] 所以这么做的话,继承该类的子类,不需要再去实现isEmpty了,只需要将size()实现就好了。 降低了实现所需的工作量,同时代码可以重用 。[设计之美]
以上函数剩下2个的实现运用到了迭代器中的方法稍后讲。
这里列出了该抽象类对Collection实现 的方法:
boolean isEmpty();
boolean contains(Object o);
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);
仍未实现的方法有
int size();
boolean equals(Object o);
int hashCode();
Iterator<E> iterator();
这4个方法
做出修改的方法:
public boolean add(E e) {
throw new UnsupportedOperationException();
}
空实现,抛出了一个异常,在之后肯定要被覆盖重写。 为什么这么做呢? 我的理解是
对之后的实现进行指示。
3.从AbstractCollection到 AbstrctList抽象类。
相比上一层的变化:
进一步重写了 add方法:
public boolean add(E e) {
add(size(), e);
return true;
}
实现了:
public Iterator<E> iterator() {
return new Itr(); //此后会对该方法重点讲
}
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
}
ListIterator<E> e1 = listIterator(); //另一条线的方法
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
到这里来自上层的仍然未有实现的方法还剩1个 int size();
这个类中还新增了抽象方法:
set(int index, E element)
get(int index)
remove(int index) (重载了Object obj的那一个)
4.从Abstract到ArrayList
看源码可以知道在ArrayList中定义了域 private int size;
并实现了方法public int size() {
return size;
}
同时对上层新增的以索引为参数的set,get,remove方法进行了实现
至此,如果我们实现了迭代器的3个方法,之前所有设计的函数内部调用的函数均有的具体的实现—>所有的函数都有了具体的实现,一个ArrayList操作集完成了!
三.迭代器到底怎么实现的呢
看了前面那么多,还是不知道迭代器在哪里实现了查看帮助文档
public interface ListIterator extends Iterator
就是从 Iterator—>ListIterator;之后没有继承的类了。关键是ListIterator是一个接口啊!!!哪有什么实现!!。没办法,于是只好根据仅有的线索去看源码。。
让我们看下面2条线
①Collection接口->List接口->AbstractList抽象类
从Colltion到List 增加了2个重要的抽象方法:
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
看起来很像C++的构造方法,但是并不是。返回值类型为2个接口引用的方法,可以判断出是返回一个实现了 ListIterator 接口的实例对象(迭代器),这里的ListIterator 就是我们上述最后一条继承线的最下层了(还未实现)。 是不是觉得我们离揭示迭代器又近了一步呢?
让我们继续往下走,AbstractList 继承了这个List接口,于是看看AbstractList的源码
找到了这个2个实现
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
第一个方法是调用第二个方法 令参数X=0实现了。在这里我们看到了newListItr(IndeX)
算上之前看到的 public Iterator iterator() {
return new Itr();
}
一共三个迭代器方法,终于看到了有new的2个部分!!!实例化啦!!不是接口 ,不是抽象类,而是真真正正可以用new实例化的类!!! 让我去看看这个ListItr 和Itr究竟是何方神圣?
打开声明:private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
哇哇哇,终于看到了Iterator接口里面定义的3个方法的实现啦!!!终于找到了!
然后上述类的一些参数可能没看过的人不清楚是干嘛的,这里就不说明了,可能下篇博客会拿出来讲讲
另外一个ListTtr类节约版面这里就稍作解释就不列源码了 ListTtr类是继承了上面这个Itr的一个子类。所以其实AbtractList中有2种迭代器。不过他们的根源都是Itr.
Itr是存在于AbtractList中的一个内部类,实现了ListIterator接口。对这个用法我也不能叙述的太清楚: 实现了ListIterator接口的Itr相当于是一个厂家/服务商,他对外提供了 Iterable接口(不要和Iterator混为一谈,一个是厂家提供具体服务要做的,一个是客户申请服务用的)一个类只要实现了Iterable接口(给钱?) 他就为这个厂家提供迭代服务。可以类比(不知道这么比对不对哈) sort方法 和comparable接口,一个类实现了compareable接口(比较原则),sort方法就为该类的数组提供排序服务)
最后一条线通过上述分析就很清楚了
②Itertor接口—>ListIerator接口 —>AbstactList抽象类的内部类。
自此迭代器的方法也全部实现了。
那么Arraylist的操作集算是彻底构成了!
四.一点小补充
其实到这里位置,ArrayList的这些对外功能已经可以用了,但是看源码可以发现
对这些已经可以用了的方法许多方法仍然进行了覆盖重写。举个例子
public boolean isEmpty() {
return size == 0;
}
这是最终ArrayList版本中的 isEmpty方法,对比之前public boolean isEmpty() {
return size() == 0;
}
为什么要可以用了还要进一步的覆盖重写呢
个人觉得是为了优化, 调用一个size()函数肯定没有直接用域值比较来的快对吧~
最后BB几句。其实在看源码的时候,是先在AbstractList里面找到了 ListIterator 的迭代器方法,才跟踪到了List那边去看。然后找到了Colleciton->list->AbstractList这条线。
而且在AbstractList 里面还有一个内部类 继承了AbstractList(内部类)为什么可以继承自己?? 而且里面还用了匿名内部类实现了相关的方法(包括迭代器)[我的天,内部类的内部类excuse me???]
最后附一个继承关系图
作者 :相赫哥哥
引用转载附作者谢谢啦~~