前言
前面我们已经分析过AbstractCollection和List这两个接口类了,接下来分析AbstractList。
AbstractList的父母
刚刚灵光一闪,想到一个不太恰当的比喻。比如AbstractList,继承了AbstractCollection,实现了List接口,那么AbstractCollection相当于是父亲,子承父业,List相当于母亲,百善孝为先,应该实现母亲的愿望(方法)。
子承父业
首先在AbstractCollection中,我们提过,AbstractCollection要求它的实现类一定要Iterator()和size()方法。而在AbstractList中,已经实现了它的Iterator()方法
public Iterator<E> iterator() {
return new Itr(); // Itr类是自己实现的
}
然后AbstractList还自己定义了一个抽象方法
abstract public E get(int index);
从这里其实就可以看出,get这个方法能根据索引index来返回元素,奠定了List这一系列里,他的实现类都是有序的,能根据索引来查找元素。
另外,要实现一个不可修改的列表,程序员只需要扩展这个类并提供get(int)和size()方法的实现。
要实现可修改的列表,程序员必须另外覆盖set(int, E)方法(否则会抛出一个UnsupportedOperationException)。 如果列表是可变大小,则程序员必须另外覆盖add(int, E)和remove(int)方法。
实现的方法
1、public int indexOf(Object o)
从头开始查找指定元素首次出现的位置
public int indexOf(Object o) {
// 获取一个list迭代器,因为使用默认构造器,当前游标位置为起始位置0,也即从前往后遍历
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
// 利用equals方法来进行比较
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
注意,这里的迭代器listIterator是AbstractList自己实现的,我们后面再详细分析。同时,要注意游标并不是直接指向元素的,而是位于元素之间,实际当循环中的if语句匹配成功时,游标已经在我们要找的那个元素后面了,所以需要返回的是前一个游标的位置。
2、public int lastIndexOf(Object o)
从后往前遍历查找指定元素首次出现的位置
public int lastIndexOf(Object o) {
// 获取一个游标位置从末尾开始的迭代器,使用有参数的构造器
ListIterator<E> it = listIterator(size());
if (o==null) {
while (it.hasPrevious())
if (it.previous()==null)
return it.nextIndex();
} else {
while (it.hasPrevious())
if (o.equals(it.previous()))
return it.nextIndex();
}
return -1;
}
3、
public void clear() 清除元素
protected void removeRange(int fromIndex, int toIndex) 范围删除元素
public void clear() {
removeRange(0, size());
}
protected void removeRange(int fromIndex, int toIndex) { // 删除包含fromIndex,不包含toIndex的范围内的元素
// 获取一个游标位于fromIndex元素之前的迭代器
ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) { // 通过i<n判断,不会删除toIndex该位置的元素
it.next();
it.remove();
}
}
4、public boolean addAll(int index, Collection<? extends E> c)
在指定的索引位置添加元素,添加的元素顺序按照给定的集合的迭代器返回元素顺序
public boolean addAll(int index, Collection<? extends E> c) {
// 索引越界检查
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
// 需要重写add(E)和add(index,E)方法,否则抛出UnsupportedOperationException异常
add(index++, e);
modified = true;
}
return modified;
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size())
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
5、public boolean equals(Object o)
重写了equals方法
在这里插入代码片
迭代器
AbstractList自己内部实现了两个迭代器:Itr和ListItr。
ListItr本身也是继承了Itr的。我们先来看Itr
Itr迭代器
先来看完整的实现代码
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
* 指向后续调用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.
* 指向最近一次调用next或previous方法返回的元素的索引。如果该元素被删除了,则重置为-1。
*/
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.
* modCount这个变量是后续的list实现类应该有的。如果违反了这一点,迭代器会出现并发的修改操作。
*/
int expectedModCount = modCount;
// 实现了Iterator接口的hasNext方法
public boolean hasNext() {
return cursor != size();
}
// 实现了Iterator接口的next方法
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();
}
}
// 实现了Iterator接口的remove方法
// 根据Iterator对remove的描述,该方法应该只有在调用过一次next方法后,才能调用该方法。
public void remove() {
// 如果lastRet<0,说明之前并没有调用过next,或者已经被移除,直接抛出异常。
if (lastRet < 0)
throw new IllegalStateException();
// 检查是否有并发操作
checkForComodification();
try {
// 调用AbstractList的子类实现的remove(index)方法
AbstractList.this.remove(lastRet);
if (lastRet < cursor)// 如果删除的元素的索引在当前游标前面,那么删除元素后,游标要向前移动一个单位
cursor--;
lastRet = -1;// 重置为-1
expectedModCount = modCount; // 一个修改操作结束后,重新设定检查并发的参数的值。
//其实这是避免子类实现了其他方法,会修改modCount值,
//造成expectedModCount与modCount不一致
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
// 检查并发修改操作
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
ListItr迭代器
// 继承Itr,实现了ListIterator,是对Itr的一个增强版
// ListItr 实现了ListIterator,支持双向遍历
private class ListItr extends Itr implements ListIterator<E> {
// 构造器,直接设定游标指向的位置
ListItr(int index) {
cursor = index;
}
// 判断前面是否还有元素
public boolean hasPrevious() {
return cursor != 0;
}
// 获取前一个元素
public E previous() {
// 检查并发操作
checkForComodification();
try {
int i = cursor - 1; // 游标向前移动一位
E previous = get(i); // 调用子类的get(index)方法
lastRet = cursor = i; // 返回刚刚查询的那个元素的索引
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
// 和remove类似,
// 根据ListIterator对set的描述,该方法应该只有在调用过一次next或者previous后,才能调用该方法。
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); // 检查并发操作
try {
// 调用实现类的set(index,E)方法
AbstractList.this.set(lastRet, e);
expectedModCount = modCount; // 操作记录数设置
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
// 在当前游标位置,调用子类的add方法插入元素
AbstractList.this.add(i, e);
lastRet = -1; // 重置lastRet
cursor = i + 1; // 插入元素后,游标位置向后移动一位
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
两个内部类
AbstractList定义了两个内部类SubList和RandomAccessSubList
我们先来看SubList
SubList
SubList本身是继承了AbstractList的,下面看源码:
class SubList<E> extends AbstractList<E> {
// 根据给出的构造器,该参数指向整个完整的List,而不是表示SubList这个子集
private final AbstractList<E> l;
// 子集对父集合的一个偏移量,
private final int offset;
// 子集的大小
private int size;
// 构造函数,截取传入的List的一部分
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
// 一系列索引边界检查
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list; // 直接指向原来的父集合
offset = fromIndex;
size = toIndex - fromIndex;
// 同步修改操作计数
this.modCount = l.modCount;
}
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
// 实质上还是调用AbstractList的方法对原集合进行操作,无非就是索引位置要额外加上偏移量
return l.set(index+offset, element);
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
public int size() {
checkForComodification();
return size;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
checkForComodification();
l.add(index+offset, element);
this.modCount = l.modCount;
size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = l.remove(index+offset);
this.modCount = l.modCount;
size--;
return result;
}
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
l.removeRange(fromIndex+offset, toIndex+offset);
this.modCount = l.modCount;
size -= (toIndex-fromIndex);
}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
l.addAll(offset+index, c);
this.modCount = l.modCount;
size += cSize;
return true;
}
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
return new ListIterator<E>() {
private final ListIterator<E> i = l.listIterator(index+offset);
public boolean hasNext() {
return nextIndex() < size;
}
public E next() {
if (hasNext())
return i.next();
else
throw new NoSuchElementException();
}
public boolean hasPrevious() {
return previousIndex() >= 0;
}
public E previous() {
if (hasPrevious())
return i.previous();
else
throw new NoSuchElementException();
}
public int nextIndex() {
return i.nextIndex() - offset;
}
public int previousIndex() {
return i.previousIndex() - offset;
}
public void remove() {
i.remove();
SubList.this.modCount = l.modCount;
size--;
}
public void set(E e) {
i.set(e);
}
public void add(E e) {
i.add(e);
SubList.this.modCount = l.modCount;
size++;
}
};
}
public List<E> subList(int fromIndex, int toIndex) {
return new SubList<>(this, fromIndex, toIndex);
}
private void rangeCheck(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
private void checkForComodification() {
if (this.modCount != l.modCount)
throw new ConcurrentModificationException();
}
}
源码看上去很长,很多,其实重点就是在开头我注释的部分,下面很多都是大同小异,无非就是实现了一些操作或者边界检查。
可以看出,SubList基本所有操作,都还是依赖于AbstractList来实现的,而且,我们在前面说过,List的subList操作,其实是保持了对原list的引用的,如果通过调用subList方法获得的list集合,进行了某些操作,其实也是对原集合进行操作,这点需要格外注意。
另一个内部类RandomAccessSubList
RandomAccessSubList是继承了SubList,实现了RandomAccess接口
这里出现了一个RandomAccess接口,我们去看它的源码
/**
* Marker interface used by <tt>List</tt> implementations to indicate that
* they support fast (generally constant time) random access. The primary
* purpose of this interface is to allow generic algorithms to alter their
* behavior to provide good performance when applied to either random or
* sequential access lists.
*
* <p>The best algorithms for manipulating random access lists (such as
* <tt>ArrayList</tt>) can produce quadratic behavior when applied to
* sequential access lists (such as <tt>LinkedList</tt>). Generic list
* algorithms are encouraged to check whether the given list is an
* <tt>instanceof</tt> this interface before applying an algorithm that would
* provide poor performance if it were applied to a sequential access list,
* and to alter their behavior if necessary to guarantee acceptable
* performance.
*
* <p>It is recognized that the distinction between random and sequential
* access is often fuzzy. For example, some <tt>List</tt> implementations
* provide asymptotically linear access times if they get huge, but constant
* access times in practice. Such a <tt>List</tt> implementation
* should generally implement this interface. As a rule of thumb, a
* <tt>List</tt> implementation should implement this interface if,
* for typical instances of the class, this loop:
* <pre>
* for (int i=0, n=list.size(); i < n; i++)
* list.get(i);
* </pre>
* runs faster than this loop:
* <pre>
* for (Iterator i=list.iterator(); i.hasNext(); )
* i.next();
* </pre>
*
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @since 1.4
*/
public interface RandomAccess {
}
根据文档解释,实际上就是一个支持快速随机访问的标识。一般有该标识的list类,遍历的时候,采用普通for循环的性能要比采用迭代器好。
再来看RandomAccessSubList类
class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
super(list, fromIndex, toIndex);
}
public List<E> subList(int fromIndex, int toIndex) {
return new RandomAccessSubList<>(this, fromIndex, toIndex);
}
}
无非就是在SubList的基础上加了个RandomAccess标识,表明它支持随机访问。
剩下的方法
如果你也是对着源码在看,可以发现,还有几个方法没有讲到。
1、public List subList(int fromIndex, int toIndex)
AbstractList实现的subList方法
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
因为涉及到两个内部类,所以放到后面来分析。
这里多了个判断,会判断当前的这个list,是否是RandomAccess或其子类的实例对象,其实就是为了区分是否支持随机访问。
2、public boolean equals(Object o)
重写了Object的equals方法
public boolean equals(Object o) {
if (o == this)
return true;
// 在运行时判断是否是List或其子类的实例对象,如果不是,直接false
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());
}
只有两个都是List或其子类的数据类型,然后判断是否包含相同的元素,且顺序一致,才能返回true。