Java 数据结构 -- 08.Java 8 数据结构 ArrayList

前言

书接上文,上一篇对 List 最终实现类(ArrayList,Vector 和 LinkedList)以外的 List 部分继承关系中的接口与类做了分析,本篇将对 ArrayList 进行分析。

先来思考几个问题

  • 容器存在的意义是什么?/为什么要使用容器?
  • 迭代器存在的意义是什么?/它对于容器来说意味着什么?

ArrayList

/**
可以重新规划容量的链表实现类。实现了所有链表的可选操作,并且容许所有原序,包括 null。除了实现了链表接口外,这个类提供了控制数组容量来内部存储链表的方法。(这个类大致与 Vector 相同,除了这个类不是线程安全的。)

size, isEmppty, get, set, iterator, listIterator 方法运行在一个时间常量中,add 方法运行在一个摊余时间常量中,这是指,添加一个元素的时间复杂度是 O(n)。所有其他操作在一个线性时间内完成。和 LinkedList 的实现类相比,常熟因子是低的。

每个数组链表对象有一个容量。容量是链表中的数组用来存储元素的个数大小。它总是至少为链表的的长度。当元素加入数组链表时,容量将会自动扩容。扩容的细节不被指定为超过添加一个有摊余常量元素因子的时间损耗。

一个应用可以通过调用 ensureCapacity 方法,传入一个大值来增加一个数组链表对象的容量。这将会减少增加重新分配的次数。

注意它的实现类不是线程安全的。如果多个线程同时访问一个数组链表对象,并且至少有一个线程多链表多了结构性的修改,则必须从外部实现线程安全。(一个结构性的修改是指任何添加或者删除一个或多个元素的操作,或者明切重定义了支持数组的大小,仅仅为一个元素设值不是一个结构性的修改。)这通常是通过使某些封装了链表的对象实现线程安全来做到的。

如果没有类似的对象存在,链表应该被使用 Collection。sychronizedList 方法进行“包装”。这最好在创建时完成,来防止意外的对链表的非线程安全的访问。

fail-fast
在这个类中。通过 iterator 方法或者 listIterator 返回的迭代器是 fail-fast 的,如果在迭代器创建后的任意时间点链表被结构性的改变了,只要不是通过迭代器自己的 ListIterator#remove 或者 ListIterator#add 方法,迭代器将会抛出一个同时修改异常。因此,对于表面上的同步更改操作,迭代器失败的快速和干净,而不是在未来的某个不确定的时间点冒险做一些不确定的行为。

注意一个迭代器的 fail-fast 行为是不能被保证的,通常来说,不可能对出现的非线程安全的同时修改操作做任何硬性的保证。基于最佳性能的基础考虑,Fail-fast 迭代器抛出一个 ConcurrentModificationException。因此,建立在这中异常上写出的程序的正确性将会是不健壮的:迭代器的 fail-fast 行为应当植被用于检查 bugs。
**/
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**默认初始容量**/
    private static final int DEFAULT_CAPACITY = 10;

    /**分配一个空实例使用的空数组**/
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**分配一个默认容量为空的实例的空数组。我们将它与 EMPTY_ELEMENTDATA 进行区分是为了了解当第一个元素加入时需要扩容多少**/
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**一个排序过的数组链表的数组缓冲。数组链表的容量是这个数组缓冲的长度。任何一个带有 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 数组的空的链表结构将在第一个元素加入的时候扩容至 DEFAULT_CAPACITY**/
    transient Object[] elementData; //不序列化的属性,非私有的,为了简化内部类访问

    /**数组链表的长度(它所包含的元素列的个数**/
    private int size;

    /**使用一个初始化容量参数来构造一个空的链表**/
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) { //如果初始容量参数大于 0
            this.elementData = new Object[initialCapacity]; //为 elementData 赋值一个新的 Object 数组,数组长度为初始容量
        } else if (initialCapacity == 0) { //如果初始容量等于 0
            this.elementData = EMPTY_ELEMENTDATA; //将 EMPTY_ELEMNTDATA 赋值给 elementData
        } else { //如果小于 0,抛出 IllegalArgumentException 异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**无参构造器**/
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //为 elemetnData 赋值 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    }

    /**使用一个组数据结构参数来构造数组链表,按照这个组数据结构的迭代器的顺序**/
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray(); //转换组数据结构为一个数组结构,并赋值给 elementData
        if ((size = elementData.length) != 0) { //elementData 的长度赋值给 size,并判断是否不为 0
            if (elementData.getClass() != Object[].class) //如果 elementData 的类不是 Object[].class
                elementData = Arrays.copyOf(elementData, size, Object[].class); //调用 Arrays.copyOf 返回一个包含元素的,长度为 size 的,类型为 Object 的新数组,赋值给 elementData
        } else {
            this.elementData = EMPTY_ELEMENTDATA; //否则将 EMPTY_ELEMENTDATA 赋值给 elementData
        }
    }

    /**修剪这个数组链表的容量到链表当前的长度。一个应用可以使用这种操作来最小化链表数组实例的存储大小**/
    public void trimToSize() {
        modCount++; //结构化改变,modCount 递增
        if (size < elementData.length) { //如果链表长度小于 elementData 的长度
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA //如果链表长度为 0,为 elementData 赋值 EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size); //否则,调用 Arrays.copyOf 方法返回一个新的包含元素的,长度为 size 的数组并赋值给 elementData
        }
    }

    /**增加这个数组链表实例的容量,如果需要,为了保证它可以持有最少为 minCapacity 参数规定的元素个数**/
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) //判断 elementData 是否不等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
            ? 0 //如果有任何长度,不是默认元素表,返回 0
            : DEFAULT_CAPACITY; //否则大于默认表。它已经被认为应该是 DEFAULT_CAPACITY,返回 DEFAULT_CAPACITY

        if (minCapacity > minExpand) { //如果 minCapacity 大于 minExpand
            ensureExplicitCapacity(minCapacity); //调用 ensureExplicitCapacity 方法,传入 minCapacity 参数
        }
    }

    /**计算容量静态私有方法,接收 elementData 与 minCapacity 参数**/
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //如果 elementData 等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
            return Math.max(DEFAULT_CAPACITY, minCapacity); //返回 DEFAULT_CAPACITY 与 minCapacity 中较大的值
        }
        return minCapacity; //返回 minCapacity
    }

    /**保证内部容量私有方法,接收 minCapacity 参数**/
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); //调用 ensureExplicitCapacity 方法,传入 elementData 与 minCapacity 参数
    }

    /**保证清晰容量方法,接收 minCapacity 参数**/
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++; //由于 grow 是结构化变更方法,需要递增 modCount

        //溢出意识代码
        if (minCapacity - elementData.length > 0) //如果 minCapacity 大于 elementData.length
            grow(minCapacity); //调用 grow 方法,传入 minCapacity
    }

    /**对于数组可分配的最大长度。一些 VM 会为一个数组保留一些头部字。试图分配更大的数组将会抛出 OutOfMemoryError**/
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**增加容量来保证它可以持有最少为 minCapacity 参数大小个数的元素**/
    private void grow(int minCapacity) {
        //溢出意识代码
        int oldCapacity = elementData.length; //将 elementData.length 赋值给 oldCapacity
        int newCapacity = oldCapacity + (oldCapacity >> 1); //将 newCapacity 赋值为 3/2 * oldCapacity
        if (newCapacity - minCapacity < 0) // 如果 newCapacity 小于 minCapacity
            newCapacity = minCapacity;  //将 minCapacity 赋值给 newCapacity
        if (newCapacity - MAX_ARRAY_SIZE > 0) //如果 newCapacity 大于 MAX_ARRAY_SIZE
            newCapacity = hugeCapacity(minCapacity); //调用 hugeCapacity 方法,传入 minCapacity 参数,将结果赋值给 newCapacity
        // minCapacity 通常与链表长度相近
        elementData = Arrays.copyOf(elementData, newCapacity); //调用 Arrays.copyOf 方法,传入 elemenetData 与 newCapacity 参数,将获得的结果赋值给 elementData
    }
    
		/**获取巨大容量静态私有方法,传入 minCapacity 参数**/
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) //如果 minCapacit 小于 0,意味着溢出
            throw new OutOfMemoryError(); //抛出 OutOfMemoryError
        return (minCapacity > MAX_ARRAY_SIZE) ? //判断 minCapacity 是否大于 MAX_ARRAY_SIZE
            Integer.MAX_VALUE : //如果是,返回 Integer.MAX_VALUE
            MAX_ARRAY_SIZE; //否则,返回 MAX_ARRAY_SIZE
    }

    /**返回链表长度**/
    public int size() {
        return size;
    }

    /**返回链表中是否存在有数据*/
    public boolean isEmpty() {
        return size == 0; //通过判断长度是否为 0
    }

    /**返回链表中是否存在与 Object 参数相同的元素**/
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    /**返回链表中与 Object 参数相同的最小下标元素位置**/
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**返回链表中与 Object 参数相同的最大下标元素位置**/
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**返回一个数组链表的浅拷贝实例(元素没有被拷贝**/
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone(); //浅拷贝当前的链表
            v.elementData = Arrays.copyOf(elementData, size); //由于 elementData 不参与序列化,所以需要单独赋值
            v.modCount = 0; //重置 modCount
            return v; //返回
        } catch (CloneNotSupportedException e) { //由于拥有克隆能力,这里应该是不会报错的
            throw new InternalError(e);
        }
    }

    /**数组链表转换成正确排序的数组的方法**/
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    /**接收一个范型数组参数,返回一个正确排序的数组的方法,返回的范型由调用这个方法的运行时范型而定。如果链表与传入参数数组合适(指大小),则会直接返回这个数组(更新后),否则将会返回一个长度重新分配的范型数组**/
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size) //如果参数的长度小于 size
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size); //否则直接调用 System.arraycopy,更新其中对应位置的元素,不新建数组
        if (a.length > size) //如果参数的长度大于 size
            a[size] = null; //数组的第 size 个元素置为 null
        return a; //返回数组 
    }

    // 下标访问操作
		//接收一个 int 参数,返回对应位置的元素
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index]; //其实调用的是数组的访问操作方式
    }

    /**接收一个 int 参数,返回对应位置的元素,与 elementData 类似,只是多了一步范围检查**/
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    /**用 E 参数在链表的 int 位置替换原来的元素**/
    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element; //其实调用的是数组的替换操作方式
        return oldValue; //返回旧值
    }

    /**在链表的最后添加 E 参数**/
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //属于结构化操作,注意要递增 modCount!!
        elementData[size++] = e;  //容量递增,并更新数组,其实调用的是数组的操作方式
        return true; //返回 true
    }

    /**在 int 参数位置插入 E 参数。向右转移当前位置和其后的元素。**/
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  //属于结构化操作,注意要递增 modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index); //通过 System.arraycopy 方法更新
        elementData[index] = element; //其实调用的是数组的替换操作方式
        size++; //容量递增
    }

    /**在 int 参数位置移除元素。向左转移其后的元素**/
    public E remove(int index) {
        rangeCheck(index);

        modCount++; //属于结构化操作,注意要递增 modCount!!
        E oldValue = elementData(index); //数组访问获得元素

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved); //更新数组
        elementData[--size] = null; //将容量递减,并将最后一个元素赋值为 null,GC 将在未来对它进行回收
        return oldValue; //返回旧值
    }

    /**移除第一个出现在链表中的与 Object 参数相等的元素,如果存在的话。如果链表不包含这种元素,它不会做任何修改**/
    public boolean remove(Object o) {
        if (o == null) { 
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) { //如果都会空
                    fastRemove(index); //调用 fastRemove 方法
                    return true; //返回 true
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) { //如果 equals 相等
                    fastRemove(index); //调用 fastRemove 方法
                    return true; //返回 true
                }
        }
        return false; //返回 false
    }

    /**私有快速移除方法,不做越界检查且不返回被移除的元素**/
    private void fastRemove(int index) {
        modCount++; //移除操作,递增 modCount
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; //递减更新 size,最后元素指为 null,GC
    }

    /**移除链表中的所有元素。调用之后链表将为空**/
    public void clear() {
        modCount++; //移除操作,递增 modCount

        //循环清楚,GC
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0; //更新 size
    }

    /**addAll 实现**/
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray(); //转为数组
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  //递增 modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew; //更新 size
        return numNew != 0; //返回长度判 0 标志
    }

    /**addAll 实现**/
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray(); 
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  //递增 modCount

        int numMoved = size - index; 
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved); //更新预留

        System.arraycopy(a, 0, elementData, index, numNew); //更新
        size += numNew; //更新 size
        return numNew != 0; //返回判 0 标志
    }

    /**removeRange 实现**/
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++; //递增 modCount
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved); //更新

        //循环赋 null,GC
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize; //更新 size
    }

    /**范围检查**/
    private void rangeCheck(int index) {
        if (index >= size) 
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); //如果参数大于等于 size 抛出 IndexOutOfBoundsException
    }

    /**add 和 addAll 时的范围检查版本**/
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); //如果参数大于 size 或者小于 0 抛出 IndexOutOfBoundsException
    }

    /**报错信息**/
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    /**removeAll 方法实现**/
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false); //调用 batchRemove 方法,传入标志为 false
    }

    /**retainAll 方法实现**/
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true); //调用 batchRemove 方法,传入标志为 true
    }

    /**批量移除私有方法,接收一个组数据参数,一个标志**/
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData; //缓存 elementData
        int r = 0, w = 0; 
        boolean modified = false;
        try {
            for (; r < size; r++) //r 循环 0 到 size
                if (c.contains(elementData[r]) == complement) //如果组数据参数包含当前链表中的数组的对应元素,并且标志为 true
                    elementData[w++] = elementData[r]; //更新缓存的 elementData(当标志为 false 的时候判断条件转为不包含)
        } finally {
            //与 AbstractCollection 的保留行为兼容
            //就算抛出了一场
            if (r != size) { //如果 r 不等于 size
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r); //更新 elementData
                w += size - r; 更新 w
            }
            if (w != size) { //如果 w 不等于 size
                //循环赋 null,GC
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w; //更新 modCount
                size = w; //更新size
                modified = true; //更新 modified
            }
        }
        return modified; //返回 modified
    }

    /**读取序列化能力实现**/
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        //缓存 modCount 到 expectedModCount 中
        int expectedModCount = modCount;
        s.defaultWriteObject(); //调用 ObjectOutputStream 参数的 defulatWriteObject 方法
        s.writeInt(size); //写入 size,作为 clone() 方法需要的容量 
        /**按正确的顺序循环写入数组中的元素**/
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }
				/**由于有循环操作,可能出现同时修改问题**/
        if (modCount != expectedModCount) { //如果 modCount 不等于 exptectedModCount
            throw new ConcurrentModificationException(); //抛出 ConcurrentModificationException 异常
        }
    }

    /**写入序列化能力实现**/
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA; //赋值 elementData 为 EMPTY_ELEMENTDATA
        s.defaultReadObject(); //调用 ObjectOutputStream 参数的 defaultReadObject 方法
        s.readInt(); //读取容量
        if (size > 0) {
            //就像 clone() 方法,根据长度分配容量,而不是容量
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity); //全县检查
            ensureCapacityInternal(size); //modCount 递增

            Object[] a = elementData; //缓存 elementData
            /**按正确的顺序循环更新数组**/
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

    /**listIterator 实现**/
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size) //参数检查
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index); //返回一个传入 index 参数的 ListItr 构造对象
    }

    /**listIterator 实现**/
    public ListIterator<E> listIterator() {
        return new ListItr(0); //返回一个参数为 0 的 ListStr 构造对象
    }

    /**iterator 实现**/
    public Iterator<E> iterator() {
        return new Itr(); //返沪一个无参的 Itr 构造对象
    }

    /**AbstractList.Itr 的优化版本**/
    private class Itr implements Iterator<E> {
        int cursor;       //游标位置值
        int lastRet = -1; //最后一个元素的位置值,如果没有则是 -1,注意这里与 AbstractList 中的实现不同了
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size; //返回游标值是否不等于容量值
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1; //步移
            return (E) elementData[lastRet = i]; //将 i 赋值给 lastRet 后更新对应位置数组元素,所以通过 next 方法,可以更新 lastRet 的值使其不处于重置状态
        }

        public void remove() {
            if (lastRet < 0) //如果 lastRet 是被重置过的,那么抛出 IllegalStateException 异常
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet); //调用 ArrayList#remove 方法,位置是 lastRet
                cursor = lastRet; //由于 lastRet 比 cursor 小 1,直接将 lastRet 赋值给 cursor
                lastRet = -1; //lastRet 重置,注意此时游标的位置不再是 0 了,但 lastRet 的值又变成了 -1
                expectedModCount = modCount; 
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]); //循环消费
            }
            /**全部操作完后,更新一次 cursor 和 lastRet 来减少堆堵塞**/
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

				/**检查同时修改问题**/
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException(); //如果不相等抛出 ConcurrentModificationException
        }
    }
    
    /**AbstractList.ListItr 的优化版本**/
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

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

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
    
    /**subList 实现**/
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex); //传入当前数组链表等参数,返回 SubList 构造对象
    }

    /**subList 范围检查方法**/
    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

    /**私有内部类 SubList**/

		/**重写 Iterable 的 forEach 方法**/
    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData; //缓存 elementData 数组
        final int size = this.size; //缓存 size
        for (int i=0; modCount == expectedModCount && i < size; i++) { //循环消费数组中的元素
            action.accept(elementData[i]); //
        }
        if (modCount != expectedModCount) { //由于循环延时,同时修改问题检查
            throw new ConcurrentModificationException();
        }
    }

    /**重写 Iterable 的 spliterator 方法,返回一个 ArrayListSpliterator 对象**/
    @Override
    public Spliterator<E> spliterator() {
        return new ArrayListSpliterator<>(this, 0, -1, 0);
    }

    /**下标基于除以 2,懒加载的并行迭代器**/
    static final class ArrayListSpliterator<E> implements Spliterator<E> {

        /*如果数组链表是不可变的,或者结构不可变的(比如没有添加,移除等操作),我们可以使用 Arrays.spliterator 实现它的并行迭代器。否则的话我们将监察与在穿行中与干涉一样多的实际操作来避免性能损耗(这句话不清楚怎么翻,有点生涩。。)。我们主要根据 modCounts。这不保证能检查到并发冲突,并且在统一线程中有时显得过于保守,但是在为了在实际中是监察带足够多的问题是值得的。为了支撑这一点,我们 (1)将初始化一个栅栏和 expectedModCount 直到我们需要提交我们检查的状态的最后一刻,因此提高了准确性。这不应用于 SubList,以及那些用当前非懒值建立的并行迭代器)。(2)我们只在 forEach 操作的最后开会检查 ConcurrentModificationException(性能最优的操作)。当使用 forEach(一个与迭代器截然不同的迭代方式),我们通常可以只监测操作结束后的干涉,而不是之前。CME-triggering(这个没有找到释义)通过所有其他可能的假定冲突,比如 null 或者过于小的 elementData 数组提供的 size() 来检查,这只可能在干涉时发生。这允许 forEach 内在的循环在运行时不需要再做更多检查,并简化了 lammda 解决问题的方式。当做完整的检查时,要注意通常情况下再一个 list.stream().forEach(a) 中,不会有在它的 forEach 循环之外的其他检查或者计算发生。其他少数时候的方法不能利用大部分的流逝操作**/
        
        private final ArrayList<E> list;
        private int index; //当前位置值,在 advance/split 时候被修改
        private int fence; //直到被使用前都为 -1,then one past last index
        private int expectedModCount; //当设置栅栏时初始化

        /**构造一个包含给定范围的并行迭代器*/
        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                             int expectedModCount) {
            this.list = list; // OK if null unless traversed
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }

        private int getFence() { //在第一次使用时候初始化 fence 为长度
            int hi; // (一个 forEach 方法专用的变量)
            ArrayList<E> lst;
            if ((hi = fence) < 0) { //fence 赋值给 hi,并判断 hi 是否小于 0
                if ((lst = list) == null) //list 赋值给 lst,并判断 lst 是否等于 null
                    hi = fence = 0; //0 赋值给 fence 与 hi
                else {
                    expectedModCount = lst.modCount; //lst 的 modCount 成员变量赋值给 expectedModCount
                    hi = fence = lst.size; //lst 的 size 成员变量赋值给 fence 和 hi
                }
            }
            return hi; //返回 hi
        }
				
				/**尝试切分方法实现**/
        public ArrayListSpliterator<E> trySplit() { 
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; //初始化 hi,lo,mid 缓存
            return (lo >= mid) ? null : //除非范围太小,否则将返回取半,返回一个新的并行迭代器
                new ArrayListSpliterator<E>(list, lo, index = mid,
                                            expectedModCount);
        }

				/**尝试前进方法实现**/
        public boolean tryAdvance(Consumer<? super E> action) {
            if (action == null)
                throw new NullPointerException(); //当 action 参数为 null 时候抛出 NullPointerException
            int hi = getFence(), i = index; //初始化 hi 和 i
            if (i < hi) {
                index = i + 1; 
                @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; //获得数组中的元素
                action.accept(e);  //消费
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }

				/**forEachRemaing 方法实现**/
        public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst; Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                }
                else
                    mc = expectedModCount; //保存 expectedModCount
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i]; //循环消费数组中的元素
                        action.accept(e);
                    }
                    if (lst.modCount == mc) //最后比较 mc 是否等于 lst 中的 modCount
                        return; //如果是返回
                }
            }
            throw new ConcurrentModificationException(); //否则抛出并行更新异常
        }

				/**估算长度方法实现**/
        public long estimateSize() {
            return (long) (getFence() - index);
        }

				/**特征值方法实现**/
        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

		/**Collection 中 removeIf 方法实现**/
    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        //判断哪些元素要被移除
        //任何断言中在这个阶段抛出的异常
        //将直接略过这个链表
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i]; //遍历缓存数组中的元素
            if (filter.test(element)) { //断言行为判断
                removeSet.set(i); //放在 removeSet 中
                removeCount++; //累加更新 removeCount
            }
        }
        if (modCount != expectedModCount) { //检查同时修改更新是否影响到了标志值
            throw new ConcurrentModificationException();
        }

        //向左移动剩余元素
        final boolean anyToRemove = removeCount > 0; //缓存删除标记
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i); //迭代获取 removeSet 中的
                elementData[j] = elementData[i];  //更新到 elementData 对应位置
            }
            for (int k=newSize; k < size; k++) {
                elementData[k] = null;  //之后的元素都置为 null,GC
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++; //累加 modCount
        }

        return anyToRemove; //返回删除标记
    }

		/**replaceAll 方法实现**/
    @Override
    @SuppressWarnings("unchecked")
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount; //缓存 modCount
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]); //循环操作数组中的元素
        }
        if (modCount != expectedModCount) { //同时修改问题
            throw new ConcurrentModificationException();
        }
        modCount++; //累加 modCount
    }

    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount; //缓存 modCount
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) { //同时修改问题
            throw new ConcurrentModificationException();
        }
        modCount++; //累加 modCount
    }
}

由 ArrayList 的源码可以看到

  • 其实数组链表就是维护了一个数组,所有 Collection 与 Iterator 相关的方法都是通过操作数组实现的,而对于数组的变更操作基本上是通过 Arrays 工具类实现的,对于数组元素的访问是直接通过访问数组下标实现的
  • 所有涉及到数组结构变更的操作都需要更新 modCount 标志,所有涉及到可能由于延时而发生的同时修改问题都通过比较操作前后的 modCount 标志值实现,类似于乐观锁的概念
  • 所谓维护数组,指的就是维护 capacity,size,modCount 等值,capacity 的扩容机制保证了数组不用在每次添加元素的时候都扩容,size 确保了数组不会越界并维护了链表中数组的长度值,modCount 维护了链表结构被更新的次数,这样可以起到维护链表结构的作用,但是维护不了其中的数据,所以说 ArrayList 是线程不安全的。
  • 对 ArrayList 的操作,只要是传入了 index 参数或者 range 参数的的操作,都是通过下标操作一个数组,不涉及到链表结构变更的操作,比如获取,更新单个值等,都是直接在 ArrayList 中通过下标获取或者更新对应值,涉及到结构变更的操作,比如在对应位置添加,删除,全部添加,全部删除等,都是通过 System.arraycopy 来做的,而这辆中操作都是高效的 ,所以可以说链表对于带 index 参数的操作都是高效的
  • 对 ArrayList 的操作,只传入了元素参数或者元素容器参数的删除操作,需要遍历整个数组逐一比较传入的参数,找到对应位置,然后再进行 System.arraycopy 操作,在链表长度很长的时候会导致效率较低,所以说说对 ArrayList 不传入 index 参数或者 range 参数的删除操作是低效的。
  • 抛出常见的 ConcurrentModificationException 异常的原因主要有两种
    (1)一种是在一个延时操作(for 迭代或者 while 迭代后),检查原来的 modCount 是否与现在的 modCount 相等,也就是“自比较”,发现不相同时抛出
    (2)还有一种是在变更了链表的结构,比如调用链表方法的添加,删除等,都会导致 modCount 递增,而此时调用迭代器的迭代方法,比如 next 方法的时候,进行 modCount 与 expectedModCount 比较,也就是“他比较”,发现不相同时抛出,而通过迭代器的对应方法对链表进行更新的时候会将 modCount 赋值给 expectedModCount 保持同步,所以说对链表结构的操作最好是使用迭代器的方法来进行
  • ArrayList 的并行迭代器是二分,懒加载的。

现在再来看之前提出的问题

  • 容器存在的意义是什么?为什么要使用容器?
    (1)容器维护了一个数组结构,数组本身是不可扩容/缩容的,容器通过 Arrays.copy 与 System.arraycopy 使得数组(看上去)有了扩容/缩容的能力。
    (2)容器维护了长度,可以以方便的方式获得数组的长度,并且维护数组结构不至于超过一个最大值。
  • 迭代器存在的意义是什么?它对于容器来说意味着什么?
    (1)如果不使用迭代器,遍历一个容器的方式是使用 for/while 循环,这种时候如果容器的结构(长度)同时发生了更改是无法判明的,通过迭代器可以判明这种情况。迭代器提供了一种安全的遍历方式。
    (2)任何传入容器参数,而需要根据容器参数的迭代器进行操作的方法,迭代器的出现屏蔽了此类方法的差异性。

下一篇将对 Vector 进行分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值