JDK类库源码分析系列3--集合类分析(2) List集合2-AbstractList

110 阅读3分钟

一、AbstractList的结构

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    ......
    protected transient int modCount = 0;
    ......

​ 其继承AbstractCollection集合抽象类,同时实现关于List集合的List接口,这里的参数modCount表示List修改的次数。

二、AbstractList中关于迭代器实现的子类

​ 下面我们来看下在AbstractList中关于Iterator接口的实现(能直接访问到AbstractList的成员变量的值)。

1、Itr

1)、成员变量

private class Itr implements Iterator<E> {

    int cursor = 0;

    int lastRet = -1;

    int expectedModCount = modCount;

​ 该子类有3个成员变量,其中:cursor表示下次获取元素的时候返回哪个位置的值、lastRet表示本次获取元素时返回的是哪个位置的值(如果该位置的元素被删除了,就重置其为-1),expectedModCount表示预期这个List被修改的次数。

2)、一些方法

public boolean hasNext() {
    return cursor != size();
}

​ 这个方法就是看cursor目前指的位置是否已经到了最后了。

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();
    }
}
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

​ 这个方法首先是判断预期修改的次数是否等于modCount修改的次数,如果不相等,可以存在并发操作这个List导致元素改变了,所以这里其是会抛一个ConcurrentModificationException的异常,如果判断满足,进行执行。就获取cursor位置的值返回,再将这个cursor(i)的值赋值给lastRet,然后cursor加一指向下次应该获取的index位置。

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();
    }
}

​ 这个首先是判断lastRet,如果小于0表示这个位置的元素已经被移除了(迭代器遍历先是next,所以next会进行lastRet对应的设置)则抛出异常,再进行检查看是否有并发修改,之后我们可以看到其是直接调用的AbstractList的remove方法,再进行cursor的自减,将lastRet置为-1,将AbstractList的modCount同步给Itr的expectedModCount。

2、ListItr

private class ListItr extends Itr implements ListIterator<E> {
    ListItr(int index) {
        cursor = index;
    }

​ 可以看到其继承了Itr同时实现了ListIterator接口,下面我们来看下其对ListIterator的方法实现

1)、关于ListIterator接口的方法实现

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();
    }
}

​ 可以看到这里与前面的next不同的是,next方法对cursor的增加是上一次操作的时候,而这里对cursor的减1是在本次。

public int nextIndex() {
    return cursor;
}
public int previousIndex() {
    return cursor-1;
}

​ 这个方法就是获取下/上一次获取元素对应的index的值。

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();
    }
}

​ 这个方法就是将新元素设置在lastRet位置。

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();
    }
}

​ 这个方法与上面对应,是设置在cursor位置。

三、方法

1、add

public boolean add(E e) {
    add(size(), e);
    return true;
}
public void add(int index, E element) {
        throw new UnsupportedOperationException();
}

​ add方法是用于添加元素,可以看到其调用的是含有index的方法(添加到对应index的位置),然后有些AbstractList的子类可能会有限制可能不能添加null值,有些子类能添加,这个add(int index, E element)方法要子类去重写,现在是直接抛的不支持操作的异常。

2、remove

public E remove(int index) {
    throw new UnsupportedOperationException();
}

3、indexOf

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 ListIterator<E> listIterator() {
    return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
    rangeCheckForAdd(index);
    return new ListItr(index);
}

​ 这个方法就是用来找到对应元素的index的位置值,其使用的迭代器实现是ListIterator,这里就是遍历判断(要明白这里it.next()再通过

it.previousIndex()返回对应的位置),没找到返回-1。

5、lastIndexOf

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;
}

​ 这个方法就是从后往前遍历,所以回去的是最后一个与o相等元素的位置,前面indexOf是获取第一个与入参相等元素的位置

6、clear

public void clear() {
    removeRange(0, size());
}
protected void removeRange(int fromIndex, int toIndex) {
    ListIterator<E> it = listIterator(fromIndex);
    for (int i=0, n=toIndex-fromIndex; i<n; i++) {
        it.next();
        it.remove();
    }
}

​ 这个方法就是迭代器遍历清空List中的元素。

7、rangeCheckForAdd

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();
}

​ 这个方法就是用来判断传入的index是不是超过了List的元素访问。

8、subList

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size());
    return (this instanceof RandomAccess ?
            new RandomAccessSubList<>(this, fromIndex, toIndex) :
            new SubList<>(this, fromIndex, toIndex));
}

​ 这个就是获取List的子集合,然后这里的RandomAccess只是用于例如遍历算法的选择,如果这个List本身有RandomAccess接口,就返回RandomAccessSubList,如果不是就返回SubList。

private static class RandomAccessSubList<E>
        extends SubList<E> implements RandomAccess {

​ 这个SubList就不展开了,这里要注意的是其等于是在原List上限制其的开始index及结束index,并没有出现copy一份新的子集合,所以如果对原List的元素修改是会对SubList中元素也改变,因为这两者是对同一对象的引用。