Java集合3:List,AbstractList和ArrayL

2019-04-07  本文已影响0人  tommy990607

List

List是一个有序集合的接口,自然就相比Collection来说就添加了一些和索引有关的方法:

void add(int index, E element);
boolean addAll(int index, Collection<? extends E> c);
default void sort(Comparator<? super E> c);
E get(int index);
E set(int index, E element);
E remove(int index);
int indexOf(Object o);      //若未找到则返回-1
int lastIndexOf(Object o);  //若未找到则返回-1

以及一些其他独有的方法:

ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
default void replaceAll(UnaryOperator<E> operator)
List<E> subList(int fromIndex, int toIndex);

值得一提的是,在Java 9之后还出了一堆静态方法,它们是用来创建不可修改的List的(也就是生成对象以后就不能新增和修改其中的元素了)

static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
...
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)

AbstractList

AbstractColletion类似,它也是系统提供的一个List接口的骨干实现,为了减轻程序员的工作量。如果要实现不可修改元素的列表,继承它并实现get(int)size()方法即可。若要实现可修改元素的列表,还需要实现set(int, E)add(int, E)remove(int)方法 (如果是长度不可变的列表的话后两个方法也可以不实现)。

它继承自AbstractColletion,也就是说它将AbstractColletion里的iterator方法给实现了,不过这个方法在本系列第一讲中就已经介绍过了hhhh

然后它也实现了List接口,将大部分方法给实现了。
这些方法都比较简单,值得一提的是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));
}

根据名字就知道这是用来生产子列表的。
这里先进行防越界检查,然后就是判断是不是RandomAccess接口的实例(这个接口,根据文档解释,就是用来表示某个列表是否支持随机访问,而不是只支持顺序访问),然后再生成SubList的对象。
SubList是个内部类,继承自AbstractList
构造函数有两个:

    /**
     * Constructs a sublist of an arbitrary AbstractList, which is
     * not a SubList itself.
     */
    public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
        this.root = root;
        this.parent = null;
        this.offset = fromIndex;
        this.size = toIndex - fromIndex;
        this.modCount = root.modCount;
    }

    /**
     * Constructs a sublist of another SubList.
     */
    protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
        this.root = parent.root;
        this.parent = parent;
        this.offset = parent.offset + fromIndex;
        this.size = toIndex - fromIndex;
        this.modCount = root.modCount;
    }

分别是用List来生成SubList,以及用SubList来生成SubList,支持多层嵌套,也就是说SubList的SubList的SubList...这种都可以。还可以看出root是指最最上层的根List,而parent则是比自己高一级的SubList。

仔细看一下其他方法:

public E set(int index, E element) {
    Objects.checkIndex(index, size);
    checkForComodification();
    return root.set(offset + index, element);
}

public E get(int index) {
    Objects.checkIndex(index, size);
    checkForComodification();
    return root.get(offset + index);
}

public void add(int index, E element) {
    rangeCheckForAdd(index);
    checkForComodification();
    root.add(offset + index, element);
    updateSizeAndModCount(1);
}

public E remove(int index) {
    Objects.checkIndex(index, size);
    checkForComodification();
    E result = root.remove(offset + index);
    updateSizeAndModCount(-1);
    return result;
}

可以看出这里的各种增删查改都是通过调用根列表的增删查改实现的。除此之外,在所有操作之前都有调用checkForComodification方法,这是不是和Iterator里的很相似hhh
不过这里是判断自己的modCount和根列表的modCount是否相等:

private void checkForComodification() {
    if (root.modCount != this.modCount)
    throw new ConcurrentModificationException();
}

它的作用也和iterator里的一样,为了避免外部类偷偷修改了数组元素的个数,从而导致内部类中size属性无法得到更新从而出错。
既然如此,那在内部类中修改了数组个数之后就需要对modCount进行更新了,这在updateSizeAndModCount方法中有具体实现:

private void updateSizeAndModCount(int sizeChange) {
    SubList<E> slist = this;
    do {
        slist.size += sizeChange;
        slist.modCount = root.modCount;
        slist = slist.parent;
    } while (slist != null);
}

大致上来说就是一直往上寻找自己的上一级SubList,把他们的modCount和size都给更新了,这样下次调用checkForComodification就不会抛出错误了。


ArrayList

上一篇下一篇

猜你喜欢

热点阅读