JDK源码阅读之AbstractList
AbstractList概述
概述来自jdk的api:
此类提供 List接口的骨干实现,以最大限度地减少实现“随机访问”数据存储(如数组)支持的该接口所需的工作。对于连续的访问数据(如链表),应优先使用
AbstractSequentialList,而不是此类。要实现不可修改的列表,编程人员只需扩展此类,并提供 get(int) 和 size() 方法的实现。
要实现可修改的列表,编程人员必须另外重写 set(int, E) 方法(否则将抛出 UnsupportedOperationException)。如果列表为可变大小,则编程人员必须另外重写 add(int, E) 和remove(int) 方法。
AbstractList类图
AbstractList 继承自 AbstractCollection 抽象类,实现了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父类。
AbstractList的两个内部迭代器
Iterator 迭代器
private class Itr implements Iterator<E> {
/**
* 游标
*/
int cursor = 0;
/**
* 上一次迭代到的元素的位置,每次使用完就会置为 -1
*/
int lastRet = -1;
/**
* 用来判断是否发生并发操作的标示,如果这两个值不一致,就会报错
*/
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--;
// 每次使用完就会置为 -1
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
这是一个简单的Iterator的实现类,主要实现了next,remove等方法,还有判断是否有并发操作。
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);
// 游标在这个时候会重合
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
ListIterator迭代器是在Iterator迭代器上扩展的,增加了add,set,previous等重要方法,提过了更多的迭代方式。
阅读到这里的时候我看源码,ListIterator的add,set方法都是调用集合的add,set方法,那么这两个方法是不是就有些多余了?
答:其实不然,因为我们在使用迭代器迭代集合的时候,可能会有需要操作集合,如果使用集合的方法来操作集合,那么就会有并发的错误。所以ListIterator添加了add,set等方法就解决了这个问题。
AbstractList的重要方法
AbstractList是不支持修改的,所以他对于修改的方法是直接抛出错误的。
AbstractList不支持的方法
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
索引方法
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
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;
}
我们从源代码中可以看到,无论是正索引还是反索引,使用的都是ListIterator迭代器。
并且都是有对null值的查询,因此在这里可以看出,List的值是可以为空的。
equals
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());
}
AbstractList的equals方式也是重写了的,与String类方法一致。会去比较元素,如果全部元素相同,那么也会判断相同。
AbstractList的两个内部类
SubList
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
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();
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++;
}
...................
}
在源码中我们可以看到SubList是继承AbstractList,并且SubList的全部方法都是使用AbstractList的,所以这个类就是AbstractList的一个包装类。
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,这个类就是在Sublist类上添加了一个接口RandomAccess,表示这个类可以支持快速访问
AbstractList源码阅读感受
这个类的代码其实还是很好阅读的,最起码是简单的,没有涉及什么高深的算法。AbstractList内部有两个迭代器,两个内部类,而且都是一层继承一层的。这种设计我觉得代码看起来会比较舒服。
说明
本文是本人撰写,如果阅读本人你有些许收获,那是我的荣幸。如果有错误或者不同意见,欢迎留言或者联系我:zlh8013gsf@126.com