1. 程式人生 > >ArrayList原始碼分析-java8

ArrayList原始碼分析-java8

1.特點總結:

  • 可儲存元素null
  • 呼叫無參構造器建立例項,預設容量capacity=10
  • 自動擴容倍數:1.5
  • 和Vector類等價,區別是 ArrayList不是執行緒安全的.
  • 4個重要的private static final型別例項變數:

    • EMPTY_ELEMENTDATA
      • 空例項的共享空陣列
      • 在capacity=0時的共享,令elementData=EMPTY_ELEMENTDATA。
      • 呼叫指定capacity構造器引數方法時,如果capacity=0,則預設的陣列就是這個
    • DEFAULTCAPACITY_EMPTY_ELEMENTDATA
      • 預設capacity空例項的共享空陣列
      • 呼叫無引數構造器時,初始化的陣列就是預設的這個。
      • 與上面變數的區別:在新增第一個元素時要擴容多少。
    • DEFAULT_CAPACITY
      • 預設的容量10
    • MAX_ARRAY_SIZE
      • 表示在java中,陣列能分配的的最大儲存空間,值為:Integer.MAX_VALUE - 8
  • 區分size和capacity

    • size<=capacity
    • size表示ArrayList中儲存了幾個元素
    • capacity表示當前elementData陣列的長度
  • java8新增方法:
    • 迭代器中:
      • forEachRemaining
    • forEach
    • 分割器中:
      • tryAdvance
      • forEachRemaining
    • removeIf
    • replaceAll

2.grow方法的自動擴容過程

這裡寫圖片描述

3.原始碼分析

    package sourcecode.analysis;

    /**
     * Created by caoxiaohong on 17/11/6 17:51.
     */

    import java.util.*;
    import java.util.function.*;
    import java.util.function.Consumer;
    import java.util.function.Predicate;
    import java.util.function.UnaryOperator;

    /**
     * ArrayList實現了List介面,是一個大小可變的陣列.
     * 它實現了list所有的可選操作,可儲存任意元素,包括null.
     * 除了實現了List介面,這個類還提供了一些運算元組大小的方法,用於內部儲存這個list.
     * 這個類可大致認為和Vector類等價,區別是 ArrayList不是執行緒安全的.
     *
     * 可在常量時間內完成的操作包括:size, isEmpty, get, set, iterator, listIterator.
     * 而add操作的時間複雜度為:分期常量時間,也就說,adding一個元素需要O(n)的時間.
     * 大致上,其它所有的操作執行時間都是線性的.
     * 和LinkedList相比,這一常量因素還是很低的.
     *
     * 每一個ArrayList例項都有一個容量.
     * 容量表示了list中儲存元素的陣列大小,它至少應該和list的size大小一致.
     * 當一個元素被add到ArrayList中,它的capacity是自動增長的.
     * 關於增長策略的細節:唯一可以確定的是新增一個元素的時間代價是常量,其它一概是不確定的.
     *
     * ArrayList例項在宣告時,如果使用了確定capacity大小的操作,那麼這一應用能夠提升這個ArrayList例項的容量.這
     * 可能會降低自動擴容的次數.
     * 說明1:
     *    Q:提升容量是什麼意思?
     *    A:ArrayList在new的時候,如果沒有指定大小,那麼會有一個預設大小的capacity,這個值為10,而指定了capacity後,capacity會改變為指定值大
     *    小。指定capacity的這一操作,會減少為ArrayList重新分配記憶體的次數(這樣效能會得到比較好的優化).
     *
     * 說明2:
     *    Q:為什麼會出現為ArrayList重新分配記憶體的時候?
     *    A:因為ArrayList在新增元素後,如果size+1>capacity,則會重新分配記憶體。
     *
     * 注意ArrayList是非執行緒安全的.如果多個執行緒同時作用於同一個ArrayList例項中的某個共同的元素,並且至少有一個執行緒更改了list的結構,那麼
     * 我們必須為其新增額外的操作以達到執行緒安全的目的.這一操作,通常是通過同步封裝在list中的幾個元素來完成的(而不是讓整個list中的元素
     * 都進行同步操作).
     * 更改list結構的操作有:
     * (1)add 或者 delete 一個或者多個元素;
     * (2)明確更改後臺陣列大小的操作;
     * 注意:僅僅更改ArrayList中某個元素的值並不屬於更改list結構的操作.
     *
     * 如果沒有這樣的物件存在,list應該使用Collections.synchronizedList這個方法將其封裝成執行緒安全的.這個封裝操作最好在list建立時候就完成,
     * 以避免在list中出現一些偶然的執行緒非同步現象.
     * 封裝方法如下:
     * List list = Collections.synchronizedList(new ArrayList(...));
     *
     * ArrayList通過方法iterator()和listIterator(int)這兩個方法返回的迭代器都會盡可能早的丟擲異常:(所謂儘可能早的是意思是:)
     * 只要是迭代器建立之後,無論在何時,採用何種方式,只要list結構發生更改,迭代器都會丟擲ConcurrentModificationException異常.
     * 注意:迭代器自己的操作remove和add則不會丟擲上述異常.
     * 因此,面對併發修改(list結構),迭代器會迅速丟擲異常而不能繼續使用,而不是去冒一種在未來不確定的某時,發生一些不確定行為的風險.
     *
     * 注意:迭代器的這種儘可能早的丟擲異常的行為並不是在出現上述更改list結構時,一定會出現的,一般來講,在出現了非執行緒安全的併發修改list結構
     * 這種現象時,不能硬性保證一定會丟擲異常.
     * 迭代器的的Fail-fast功能,只是儘可能的丟擲ConcurrentModificationException這一異常.
     * 因此,如果一個程式的正確性完全依賴Fail-fast這一異常的話,這是一種錯誤的方式:迭代器的Fail-fast行為僅僅應該被用來查詢bug.
     *
     * @author  Josh Bloch
     * @author  Neal Gafter
     * @see     Collection
     * @see     List
     * @see     LinkedList
     * @see     Vector
     * @since   1.2
     */

    /**
     * 從類名處分析:
     * (1)ArrayList<E>:表明ArrayList支援泛型
     * (2)繼承1個類:AbstractList 繼承了AbstractCollection類,並且含概了List介面方法的預設實現.
     * (3)實現4個介面:
     *   List:定義了列表必須實現的操作方法.
     *   RandomAccess:這是一個標記介面,接口裡面沒有任何方法和欄位.這一介面存在的意義:實現了這一介面的類支援隨機訪問元素.對於一個被訪問的列表來說,
     *                不管是隨機訪問還是順序訪問,這一介面的原始目的就是允許其通過泛型演算法來更改其行為,來達到更好的效能.
     *   Cloneable: 接口裡面沒有任何方法和欄位,實現了這個介面的類,才能使得呼叫java.lang.Object.clone()方法才是合法的.但是當前類必須通過override
     *              Object的clone()這個方法,才能使得這一功能得到實現.這個方法會返回當前類例項的一份淺拷貝.關於淺拷貝:比如ArrayList的
     *              clone()方法:只拷貝了其儲存內容和當前例項list結構的修改次數modCount,同時modCount在拷貝時被置為0.
     *   java.io.Serializable:這也是一個裡面沒有任何方法和欄位的介面,只有實現這一介面的類才允許被序列化.沒有實現這一介面的類不允許序列化和反序
     *                        列化.如果一個類的父類是序列化的,那麼這個子類自然也是可以序列化的.
     * @param <E>
     */
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {

         //接下來是5個private型的例項變數,且前3個為常量.且前4個不會被序列化.

        /**
         * serialVersionUID:是JVM對位元組流進行反序列化的標準.
         * 如果被反序列化的位元組流中的serialVersionUID和本地相應的java實體或者物件一致,則當然輸入位元組流可以進行反序列化;否則,會丟擲InvalidClassException異常.
         */
        private static final long serialVersionUID = 8683452581122892189L;

        /**
         * 預設的容量10,也就是在add操作不超過10個時, ArrayList不會進行擴容,超過後才進行擴容.
         * 嚴重區別:capacity和size的區別
         * capacity表示:在ArrayList擴容前,一共能容納多少個元素.也就是底層陣列的length
         * size:表示ArrayList當前真正儲存了幾個元素.
         * 關係:capacity>=size
         */
        private static final int DEFAULT_CAPACITY = 10;


         //空例項的共享空陣列.
        private static final Object[] EMPTY_ELEMENTDATA = {};

        /**
         * 預設size空例項的共享空陣列
         * 我們將這與EMPTY_ELEMENTDATA區分開來,以知道在新增第一個元素時要擴容多少。
         * 這一變數是JDK8新增的
         */
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

        /**
         * elementData是ArrayList的元素陣列緩衝區,這是add操作的儲存位置.
         * ArrayList的容量是這個陣列緩衝區的長度。
         * 當新增第一個元素時,任何具有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
         * 的空ArrayList將容量擴為:10=DEFAULT_CAPACITY
         * 這一變數序列化時,為null
         *
         */
        private transient Object[] elementData;

        //ArrayList 實際儲存了幾個元素
        private int size;



        /*---------ArrayList的3個建構函式----------*/

        //構造方法傳入預設的容量capacity,設定預設陣列大小為指定capacity的大小.
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) { //初始化容量指定為0,則用EMPTY_ELEMENTDATA陣列
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                        initialCapacity);
            }
        }

        //建立一個預設容量為10的空陣列例項,用到了java8新增變數DEFAULTCAPACITY_EMPTY_ELEMENTDATA.
        public ArrayList() {
            super();
            //jdk7程式碼:this.elementData=EMPTY_ELEMENTDATA
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }

        /**
         * 構造方法傳入一個Collection,再將Collection中的元素copy到ArrayList的陣列elementData中.
         * 如果通過Collection得到的陣列elementData型別不是Object[]型別,則將其轉為Object[]型別.
         */
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            if ((size = elementData.length) != 0) {
                //反射,獲取陣列型別,判定c.toArray型別是否為Object[]型別
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }

        /**
         * 縮減ArrayList例項的capacity為當前儲存元素個數的大小.
         * 這一方法的存在意義:如果capacity被分配過大,那麼應用可以通過這個操作,將ArrayList例項的capacity的大小改為當前ArrayList例項
         * 儲存元素的個數,從而達到縮減ArrayList儲存空間大小的目的.
         */
        public void trimToSize() {
            modCount++;
            if (size < elementData.length) {
                elementData = (size == 0)
                        ? EMPTY_ELEMENTDATA
                        : Arrays.copyOf(elementData, size);
            }
        }

        /**
         * 如果需要,增加此ArrayList例項的容量,以確保它至少能容納最小容量引數指定的元素數量。
         * 兩種表示式:
         * 如果add的是一個元素,則minCapacity=size+1;
         * 如果add的是一個Collection,則minCapacity=size+Collection.size;
         * @param   minCapacity   the desired minimum capacity
         */
        public void ensureCapacity(int minCapacity) {
            //最小擴容量
            int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                    // 如果elementData不是預設空陣列,則擴容大小任意,這裡預設為0
                    ? 0
                    //如果elementData是預設空陣列,則擴容預設為10
                    : DEFAULT_CAPACITY;
            //如果最小容量>最小擴容量,則可能進行擴容,是否擴容取決於elementData.length
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }

        private void ensureCapacityInternal(int minCapacity) {
            if (elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                //最小容量:max(10,minCapacity)
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
            //針對最小容量,決定是否擴容
            ensureExplicitCapacity(minCapacity);
        }

        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;

            // overflow-conscious code
            /**
             * 增加元素後,ArrayList中應該儲存的元素個數為minCapacity,
             * 所以,如果此時minCapacity>後臺陣列的長度(elementData.length),則要按照minCapacity進行擴容啦
             */
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }

        /**
         * MAX_ARRAY_SIZE:表示在java中,陣列能分配的的最大儲存空間.
         * 一些虛擬機器會在陣列中保留一些標題字.
         * 如果嘗試分配比MAX_ARRAY_SIZE更大的儲存空間,可能會導致記憶體溢位異常:請求陣列大小超過了虛擬機器的限制.
         */
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

        /**
         * 根據給定傳入引數:最小capacity,來為ArrayList進行擴容.
         * 這是面試中經常問到的問題:ArrayList是如何擴容的?其實程式碼如此簡短且易理解.
         * @param minCapacity the desired minimum capacity
         */
        private void grow(int minCapacity) {
            // overflow-conscious code
            //獲取原後臺陣列的長度
            int oldCapacity = elementData.length;
            /**注意:這裡就是所謂的按照1.5倍進行擴容的思想.顯然如果如果原陣列長度為偶數,
             *     那麼新陣列長度就恰好是原後臺陣列的1.5倍;如果原後臺陣列的長度為奇數,則新陣列長度應該比1.5倍少一個.**/
            //新陣列的長度=原後臺陣列的長度+原後臺陣列的長度/2
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            //如果按照1.5倍進行擴容後,capacity仍然比實際需要的小,則新陣列的長度由原來的1.5倍  更改為 實際需要的大小minCapacity.
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            //如果新陣列的長度比虛擬機器能夠提供給陣列的最大儲存空間大,則將新陣列長度更改為最大正數:Integer.MAX_VALUE
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            // 所謂擴容,就是按照新的長度newCapacity建立一個新陣列並返回,然後再將原陣列中的內容copy到新陣列中.
            elementData = Arrays.copyOf(elementData, newCapacity);
        }

        private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                    Integer.MAX_VALUE :
                    MAX_ARRAY_SIZE;
        }

       //返回ArrayList中儲存的元素個數
        public int size() {
            return size;
        }

       //根據ArrayList中是否有儲存的元素,返回true或者false.根據size==0來判定的.
        public boolean isEmpty() {
            return size == 0;
        }

        /**
         * 檢視ArrayList中是否存在指定元素.
         * 存在指定元素1個及以上,則返回true;
         * 否則,返回false;
         */
        public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }

        /**
         *
         * 這個方法唯一需要注意的:將查詢物件o分為兩種情況來查詢:
         * (1)如果o為null,用==
         * (2)如果o為Object,用equals
         * 因為:==比較的是地址或者是常量,而equals比較的是物件的內容.
         */
        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;
        }

        //此方法功能沒什麼好說的,注意事項也和上面的方法一樣.
        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;
        }

        /**
         * 這是對ArrayList例項的一個淺拷貝,即將ArrayList例項中的內容拷貝到一個新的ArrayList中,
         * 並且新的ArrayList中的操作不會對原ArrayList產生影響.
         */
        public Object clone() {
            try {
                ArrayList<E> v = (ArrayList<E>) super.clone(); //內容拷貝
                v.elementData = Arrays.copyOf(elementData, size); //為新的ArrayList的後臺陣列賦值
                v.modCount = 0; //為新的ArrayList的結構更改次數字段賦值為0.
                return v; //返回新陣列.
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }

        /**
         * 這又是一個淺拷貝的方法.將後臺陣列elementData中的內容賦值為一個新的Object[],並返回.
         * Object[]中元素的順序和原後臺陣列elementData中的一致.
         * 對新的Object[]的操作不會影響後臺陣列elementData.
         * 這一方法被看作是:連線陣列和集合的橋樑.
         */
        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }

        /**
         * 功能:將ArrayList轉為陣列
         * 方法返回型別:和a一致.
         * 方法返回陣列大小:和a的大小有關.
         * 如果a.length<size,則返回陣列大小為size.
         * 如果a.length>=size,則返回陣列大小為a.length.
         *
         * 是否一定生成一個新陣列:不一定.
         * 如果a.length<size,則會生成一個新的陣列,並返回.
         * 如果a.length>=size,則不會生成新的陣列.
         */
        public <T> T[] toArray(T[] a) {
            if (a.length < size)
                //產生一個新的執行時陣列,但陣列內容不變
                return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            //如果a.length>=size,則通過系統拷貝將a中元素拷貝到elementData中
            System.arraycopy(elementData, 0, a, 0, size);
            //如果a.length>size,則將a[size]=null,通知jvm可回收此空間
            if (a.length > size)
                a[size] = null;
            return a;
        }
        /**
         * 陣列的隨機訪問:
         * 將訪問封裝為方法的目的:
         * 主要是避免每次取值都要強轉===>設定值就沒有封裝成一個方法,因為設定值不需要強轉
         * @param index
         * @return
         */
        //  指定位置訪問操作
        E elementData(int index) {
            return (E) elementData[index];
        }

        //返回後臺陣列elementData[index]的值.
        public E get(int index) {
            //索引合法性判定
            rangeCheck(index);

            return elementData(index);
        }

        //替換陣列elementData指定位置index的值為element
        public E set(int index, E element) {
            //索引合法性判定
            rangeCheck(index);
            //舊值儲存
            E oldValue = elementData(index);
            elementData[index] = element;
            //返回舊值
            return oldValue;
        }

        //在陣列elementData結尾新增一個元素
        public boolean add(E e) {
            //容量合法性判定
            ensureCapacityInternal(size + 1);  // 結構更改次數:modCount更改
            elementData[size++] = e;
            return true;
        }

        //在後臺數組elementData指定位置index處新增元素element.
        public void add(int index, E element) {
            //索引合法性判定
            rangeCheckForAdd(index);
            //容量合法性判定
            ensureCapacityInternal(size + 1);  //結構更改次數:modCount更改
            //系統拷貝
            System.arraycopy(elementData, index, elementData, index + 1,
                    size - index);
            elementData[index] = element;
            size++;
        }

        /**
         * 將後臺陣列elementData指定位置index處的元素刪除,然後左移索引index後面的元素.
         * 並將刪除元素作為結果返回.
         */
        public E remove(int index) {
            rangeCheck(index);//範圍合法性檢查

            modCount++;//結構更改次數+1
            E oldValue = elementData(index);//儲存舊值

            int numMoved = size - index - 1;//移動元素個數
            if (numMoved > 0) //如果有有需要向前移動的元素
                System.arraycopy(elementData, index+1, elementData, index,
                        numMoved);
            //注意這裡啦:null的賦值,為JVM進行GC做了準備工作
            elementData[--size] = null; // clear to let GC do its work

            return oldValue;
        }

        /**
         * 刪除ArrayList中指定的元素,如果這個元素在ArrayList中存在多個,則只刪除最先出現的那個.
         * 如果不存在,返回結果false,表示刪除失敗.
         */
        public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);//呼叫快速remove方法
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);//呼叫快速remove方法
                        return true;
                    }
            }
            return false;
        }

        //私有快速remove方法,跳過邊界檢查,且不返回舊值
        private void fastRemove(int index) {
            //增加結構更改次數
            modCount++;
            //右移元素個數
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                        numMoved);
            //通知JVM進行可用對其進行GC操作
            elementData[--size] = null; // clear to let GC do its work
        }

        /**
         * 清空後臺陣列elementData中的元素.
         * 它會將elementData中所有的元素置為null.
         * 並且重新設定size為0.
         */
        public void clear() {
            modCount++;

            //注意這裡啦:null的賦值,為JVM進行GC做了準備工作.
            for (int i = 0; i < size; i++)
                elementData[i] = null;

            size = 0;
        }

        /**
         * 將集合c中的元素順次新增到ArrayList例項尾部.
         * 這裡注意一個問題:因為ArrayList是非執行緒安全的,所以,如果在將c中的元素新增到ArrayList中時,
         * c結構被更改了,這可能會出現問題.
         */
        public boolean addAll(Collection<? extends E> c) {
            //轉為Object陣列
            Object[] a = c.toArray();
            //獲取陣列長度
            int numNew = a.length;
            //容量合法性判定
            ensureCapacityInternal(size + numNew);  // Increments modCount
            //系統拷貝到elementData
            System.arraycopy(a, 0, elementData, size, numNew);
            //更改size
            size += numNew;
            return numNew != 0;
        }

        /**
         * 將傳入集合c中的元素新增到ArrayList例項,新增開始的位置為指定的index.
         * 工作過程:
         * 首先,重置elementData的大小;
         * 然後,向後移動elementData中下標範圍為:[index,index+numNew)的元素.
         * 最後,將c中的元素拷貝到elementData中,elementData的拷貝位置從下標index開始.
         */
        public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);

            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments 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;
            return numNew != 0;
        }

        /**
         * 移除ArrayList例項中下標為[fromIndex,toIndex)的元素.
         * 注意:刪除包括下標為fromIndex的元素,但不包括下標為toIndex的元素.
         */
        protected void removeRange(int fromIndex, int toIndex) {
            modCount++;
            int numMoved = size - toIndex;
            System.arraycopy(elementData, toIndex, elementData, fromIndex,
                    numMoved);

            //這裡又有和GC相關的操作啦
            int newSize = size - (toIndex-fromIndex);
            for (int i = newSize; i < size; i++) {
                elementData[i] = null;
            }
            size = newSize;
        }

        /**
         * 這個方法唯一注意地方:就是對於給定的陣列下標index沒有判定為負數情況,為什麼沒有判定?
         * answer: 因為這一方法總是在訪問陣列之前被呼叫,如果index為負數,則丟擲ArrayIndexOutOfBoundsException.
         * 所以這裡沒有必要再判定一次index為負數的情況.那樣就很冗餘啦.
         */
        private void rangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        //本方法用於:add方法或者addall方法,檢查插入位置index的合法性.
        private void rangeCheckForAdd(int index) {
            if (index > size || index < 0)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        /**
         * 此方法功能:用於收集IndexOutOfBoundsException異常的細節資訊.
         * 在錯誤處理程式碼的許多可能的重構中,這一構造方式對於伺服器和客戶端的虛擬機器表現都最好.
         */
        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+size;
        }

        /**
         * 移除ArrayList例項中,和集合c中一樣的元素.
         * 注意:如果集合c中不允許有null值,但是ArrayList例項中有,則會丟擲NullPointerException異常.
         */
        public boolean removeAll(Collection<?> c) {
            Objects.requireNonNull(c);
            return batchRemove(c, false);
        }

        /**
         * 移除ArrayList中元素:
         * 被移除元素滿足的條件是:在ArrayList例項中存在,而在集合c中不存在.
         */
        public boolean retainAll(Collection<?> c) {
            Objects.requireNonNull(c);
            return batchRemove(c, true);
        }

        /**
         * 批量刪除方法
         * 這個方法是上面兩個方法的輔助方法:
         * 非常喜歡的一處程式碼:try裡面的for迴圈程式碼,很優雅的程式碼,完成了兩個方法的功能,如果是自己就估計寫成if判定了...
         */
        private boolean batchRemove(Collection<?> c, boolean complement) {
            final Object[] elementData = this.elementData;
            int r = 0, w = 0;//r記錄從左到右遍歷了list中幾個元素; w記錄了list中留下了幾個元素
            boolean modified = false;
            try {
                for (; r < size; r++) //將符合條件的elementData中的元素左移.
                    if (c.contains(elementData[r]) == complement)
                        elementData[w++] = elementData[r];
            } finally {
                /**
                 * 這裡的程式碼:是為了保持和AbstractCollection行為的相容性.
                 * 儘管在上述的c.contains裡面應該也會丟擲異常的.但是這裡還是處理了一下.
                 *
                 * 下面分析兩個if的功能:
                 * 第一個if:表面上看起來r!=size的條件永遠不會得到滿足,因為上述try裡面一直在r++呀.但是,你不要忘記,c.contains是可能丟擲兩類
                 * 異常的:ClassCastException和NullPointerException,這就會導致進入finally裡面,也就執行了這個if語句.
                 *
                 * 第二個if:又是GC啦,將elementData下標從w開始的值置為null,以便告訴JVM可以對elementData下標為[w,size-1]的位置進行回收啦.
                 */
                //try裡面的for迴圈未完成
                if (r != size) {
                    System.arraycopy(elementData, r,
                            elementData, w,
                            size - r);
                    w += size - r;
                }
                //原elementData後面有刪除元素
                if (w != size) {
                    // clear to let GC do its work
                    for (int i = w; i < size; i++)
                        elementData[i] = null;
                    modCount += size - w;
                    size = w;
                    modified = true;
                }
            }
            return modified;
        }

        /**
         * 將ArrayList進行序列化:儲存一個ArrayList的狀態到輸出流中.
         * 注意2點:
         * 1.在將elementData中的元素寫入到輸出流之前,先將elementData的size寫入到輸出流中.
         * 之前一直以為只向輸出流中寫入elementData中的資料呢.
         * 2.defaultWriteObject方法功能:寫入類的no-static和no-transient欄位到輸出流中.
         * 那麼問題來了,size應該是在這裡就被寫入到輸出流了,那麼下面為什麼還有s.writeInt(size)這一句,是否重複呢?
         * answer: 原始碼給出的解釋是:作為clone()方法的相容行為,且被作為capacity欄位進行儲存.同時,我們可以在方法readObject中發現,
         * 在通過方法defaultReadObject讀取了size以及其它隱藏屬性後,下一個讀取的int資料就是capacity.根據順序輸出和順序讀取的特點,我們知道
         * 這個capacity就是我們在writeObject方法中s.writeInt(size).
         *
         * 3.defaultWriteObject方法再分析:,
         * defaultReadObject()和defaultWriteObject()應該是readObject(ObjectInputStream o)和
         * writeObject(ObjectOutputStream o)中的第一個方法呼叫。這些方法也有助於向後相容.如果將來你為這個類添加了一些非瞬態的欄位,
         * 並且你試圖通過舊版本的類來反序列化它,那麼defaultReadObject()方法將會忽略新新增的欄位,類似地,如果你通過新的反序列化舊的
         * 序列化物件版本,那麼新的非瞬態欄位將採取JVM中的預設值,比如int為0,boolean為false等.
         */
        private void writeObject(java.io.ObjectOutputStream s)
                throws java.io.IOException{
            // Write out element count, and any hidden stuff
            int expectedModCount = modCount;
            s.defaultWriteObject();

            // Write out size as capacity for behavioural compatibility with clone()
            s.writeInt(size);

            // Write out all elements in the proper order.
            for (int i=0; i<size; i++) {
                s.writeObject(elementData[i]);
            }

            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }

        //根據stream中的描述資訊,構造一個ArrayList例項
        private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
            elementData = EMPTY_ELEMENTDATA;

            //讀入size欄位值和其它隱藏屬性值
            // Read in size, and any hidden stuff
            s.defaultReadObject();

            //讀入capacity欄位值
            // Read in capacity
            s.readInt(); // ignored

            if (size > 0) {
                //基於size而非capacity進行記憶體分配
                // be like clone(), allocate array based upon size not capacity
                ensureCapacityInternal(size);

                Object[] a = elementData;
                // Read in all elements in the proper order.
                for (int i=0; i<size; i++) {
                    a[i] = s.readObject();
                }
            }
        }

        /*--------3個不同型別迭代器的方法-------全都是fail-fast型別的.*/

        //從指定下標index開始遍歷ArrayList例項,包含index.
        public ListIterator<E> listIterator(int index) {
            if (index < 0 || index > size)
                throw new IndexOutOfBoundsException("Index: "+index);
            return new ListItr(index);
        }

        public ListIterator<E> listIterator() {
            return new ListItr(0);
        }

        public Iterator<E> iterator() {
            return new Itr();
        }

        /**
         * An optimized version of AbstractList.Itr
         * 這個方法是上述3個迭代器方法中第3個方法的輔助方法,也是它的核心演算法實現.
         * 關於cursor和陣列元素下標的關係,這裡再次書寫一遍.例如elementData={1,2,3},則陣列下標分別為0,1,2,那麼加上類cursor後,該有的形式是:
         * cursor0,0,cursor1,1,cursor2,2,cursor3.
         * 也就是說cursor的值是在陣列元素之間的值,故cursor並不指向陣列元素.所以如果elementData長度為size,則cursor值有size+1個.
         *
         * 還要注意一點:Itr是個內部類.所以上述3個方法在呼叫時候,會使用到new欄位,來生成這個內部類,然後才能呼叫這個類裡面的方法.
         */
        private class Itr implements Iterator<E> {
            int cursor;       // index of next element to return
            int lastRet = -1; // index of last element returned; -1 if no such
            /**
             * new這個類的時候,首先獲取當前ArrayList例項的modCount的值,是為了在進行迭代的時候,隨時檢查ArrayList例項的結構是否被更改,
             * 一旦被更改,則儘可能早的丟擲異常.這點就是迭代器丟擲ConcurrentModificationException()一次的依據.
             */
            int expectedModCount = modCount;

            public boolean hasNext() { //cursor取值範圍:[0,size]
                return cursor != size;
            }

            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                /**
                 * 每次next,都要宣告一個Object[] elementData,為什麼不在開始初始化類Itr時就宣告?
                 * 感覺好像應該是這樣的:就是這個引用基本和其它方法完全沒有關係,也就是elementData中的資料只和next()取值有關係,那麼每次呼叫
                 * next()方法時,就獲取一遍elementData的引用就行了.反正獲取引用也不會生成新的儲存空間,造成資源的浪費.這樣封裝起來的方法
                 * 看起來更舒服.
                 */
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];//既返回了需要的值,又完成了對lastRet的賦值,完美!!!
            }

            /**
             * 注意啦:這個方法是迭代器的remove方法,之前就說過,如果ArrayList例項在生成迭代器之後,如果再直接對ArrayList例項
             * 改變結構的化,迭代器會丟擲異常ConcurrentModificationException.
             * 但是通過迭代器對ArrayList例項進行結構對改變,則不會丟擲異常.這是怎麼辦到的呢?這就歸因於下面try裡面的程式碼啦.
             * ok,分析一下try裡面的程式碼工作過程:
             * 已經在每行程式碼後面寫好了……^_^
             *
             * 還有一點要注意的是:remove()方法刪除的就是ArrayList例項中的元素值,但這不影響對elementData的遍歷.因為每次刪除對都是
             * 上一次已經遍歷過對值,這一點通過ArrayList.this.remove(lastRet)和cursor = lastRet可以知道.
             * 所以remove()方法的實質:就是一邊遍歷,一遍刪除.刪除的都是上一次訪問的元素.最後elementData中元素全為null.
             */
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();

                try {
                    ArrayList.this.remove(lastRet);//刪除ArrayList例項中下標為lastRet的元素
                    cursor = lastRet; //將cursor值更新到上一次訪問元素的下標值,也就是cursor=cursor-1.
                    lastRet = -1; //將上一次訪問元素的陣列下標置為-1,也就是初始化.
                    expectedModCount = modCount;//更新ArrayList例項結構被修改的次數,也就是expectedModCount=expectedModCount+1.
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

            @Override
            @SuppressWarnings("unchecked")
            public void forEachRemaining(java.util.function.Consumer<? super E> consumer) {
                //傳入函式介面不為空
                Objects.requireNonNull(consumer);
                //記錄size大小
                final int size = ArrayList.this.size;
                //記錄遊標
                int i = cursor;
                //如果遊標到達最後一個元素的後面
                if (i >= size) {
                    return;
                }
                //記錄當前elementData陣列
                final Object[] elementData = ArrayList.this.elementData;
                //如果遊標>elementData陣列長度
                if (i >= elementData.length) {
                    throw new ConcurrentModificationException();
                }
                //對遊標後的每一個元素都執行函式介面定義對accept操作.
                while (i != size && modCount == expectedModCount) {
                    consumer.accept((E) elementData[i++]);
                }
                // update once at end of iteration to reduce heap write traffic
                //更新遊標
                cursor = i;
                //更新上一個訪問元素的下標值
                lastRet = i - 1;
                //併發檢查
                checkForComodification();
            }

            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }

        /**
         * 這個方法是上面3個迭代方法中前2個方法中被呼叫的方法.
         * 這個方法是對AbstractList中的方法ListItr的優化版本.
         * 這裡有2處要注意的地方:
         * (1)set方法:不改變ArrayList的結構,只改變上一次訪問的ArrayList中的元素值.
         * (2)add方法:改變ArrayList的結構,新增元素的位置是:上一次訪問的ArrayList中的元素的位置.
         *
         * 不管呼叫set方法還是add方法,ArrayList例項通過迭代器輸出的內容都不會改變.
         */
        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()方法的介紹.讀懂了上面所有的程式碼,再看下面這些簡直太容易了.
         * 但是但是但是,重要事情說三遍:
         * 還是有要非常注意的地方,也是容易引起誤解的地方:
         * subList()這個方法,功能是返回指定列表的部分檢視;
         * 但是,它不是在java堆中新開闢的一個list物件,而是一個原列表檢視的一部分,因此不管這兩個列表誰發生了變化,都會體現在另一個列表上面.
         * 這就和資料庫中的檢視一樣,對檢視的操作其實最終還是對生成檢視的基本表的操作,而對於基本表的操作導致資料發生改變時,也會體現在檢視上面.
         */

        public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, 0, fromIndex, toIndex);
        }

        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 + ")");
        }

        private class SubList extends AbstractList<E> implements RandomAccess {
            private final AbstractList<E> parent;
            private final int parentOffset;
            private final int offset;
            int size;

            SubList(AbstractList<E> parent,
                    int offset, int fromIndex, int toIndex) {
                this.parent = parent;//設定了父類,從而為後面基於父類的操作做了準備工作
                this.parentOffset = fromIndex;
                this.offset = offset + fromIndex;
                this.size = toIndex - fromIndex;
                this.modCount = ArrayList.this.modCount;
            }

            public E set(int index, E e) {
                rangeCheck(index);
                checkForComodification();
                E oldValue = ArrayList.this.elementData(offset + index);
                ArrayList.this.elementData[offset + index] = e;
                return oldValue;
            }

            public E get(int index) {
                rangeCheck(index);
                checkForComodification();
                return ArrayList.this.elementData(offset + index);
            }

            public int size() {
                checkForComodification();
                return this.size;
            }

            public void add(int index, E e) {
                rangeCheckForAdd(index);
                checkForComodification();
                parent.add(parentOffset + index, e);//為父類增加一個值
               // this.modCount = parent.modCount; //更改父類的結構改變計數器
                this.size++;
            }

            public E remove(int index) {
                rangeCheck(index);
                checkForComodification();
                E result = parent.remove(parentOffset + index);//為父類刪除一個值
                //this.modCount = parent.modCount;//更改父類的結構改變計數器
                this.size--;
                return result;
            }

            protected void removeRange(int fromIndex, int toIndex) {
                checkForComodification();
    //            parent.removeRange(parentOffset + fromIndex,
    //                    parentOffset + toIndex);
    //            this.modCount = parent.modCount;//更改父類的結構改變計數器
                this.size -= toIndex - fromIndex;
            }

            public boolean addAll(Collection<? extends E> c) {
                return addAll(this.size, c);
            }

            public boolean addAll(int index, Collection<? extends E> c) {
                rangeCheckForAdd(index);
                int cSize = c.size();
                if (cSize==0)
                    return false;

                checkForComodification();
                parent.addAll(parentOffset + index, c);//呼叫父類方法,為父類elementData增加新元素.
                //this.modCount = parent.modCount;//更改父類的結構改變計數器
                this.size += cSize;
                return true;
            }

            public Iterator<E> iterator() {
                return listIterator();
            }

            public ListIterator<E> listIterator(final int index) {
                checkForComodification();
                rangeCheckForAdd(index);
                final int offset = this.offset;

                return new ListIterator<E>() {
                    int cursor = index;
                    int lastRet = -1;
                    int expectedModCount = ArrayList.this.modCount;

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

                    @SuppressWarnings("unchecked")
                    public E next() {
                        checkForComodification();
                        int i = cursor;
                        if (i >= SubList.this.size)
                            throw new NoSuchElementException();
                        Object[] elementData = ArrayList.this.elementData;
                        if (offset + i >= elementData.length)
                            throw new ConcurrentModificationException();
                        cursor = i + 1;
                        return (E) elementData[offset + (lastRet = i)];
                    }

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

                    @SuppressWarnings("unchecked")
                    public E previous() {
                        checkForComodification();
                        int i = cursor - 1;
                        if (i < 0)
                            throw new NoSuchElementException();
                        Object[] elementData = ArrayList.this.elementData;
                        if (offset + i >= elementData.length)
                            throw new ConcurrentModificationException();
                        cursor = i;
                        return (E) elementData[offset + (lastRet = i)];
                    }
                    //jdk8新增
                    @SuppressWarnings("unchecked")
                    public void forEachRemaining(Consumer<? super E> consumer) {
                        Objects.requireNonNull(consumer);
                        final int size = SubList.this.size;
                        int i = cursor;
                        if (i >= size) {
                            return;
                        }
                        final Object[] elementData = ArrayList.this.elementData;
                        if (offset + i >= elementData.length) {
                            throw new ConcurrentModificationException();
                        }
                        while (i != size && modCount == expectedModCount) {
                            consumer.accept((E) elementData[offset + (i++)]);
                        }
                        // update once at end of iteration to reduce heap write traffic
                        lastRet = cursor = i;
                        checkForComodification();
                    }

                    public int nextIndex() {
                        return cursor;
                    }

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

                    public void remove() {
                        if (lastRet < 0)
                            throw new IllegalStateException();
                        checkForComodification();

                        try {
                            SubList.this.remove(lastRet);
                            cursor = lastRet;
                            lastRet = -1;
                            expectedModCount = ArrayList.this.modCount;
                        } catch (IndexOutOfBoundsException ex) {
                            throw new ConcurrentModificationException();
                        }
                    }

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

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

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

                        try {
                            int i = cursor;
                            SubList.this.add(i, e);
                            cursor = i + 1;
                            lastRet = -1;
                            expectedModCount = ArrayList.this.modCount;
                        } catch (IndexOutOfBoundsException ex) {
                            throw new ConcurrentModificationException();
                        }
                    }

                    final void checkForComodification() {
                        if (expectedModCount != ArrayList.this.modCount)
                            throw new ConcurrentModificationException();
                    }
                };
            }

            public List<E> subList(int fromIndex, int toIndex) {
                subListRangeCheck(fromIndex, toIndex, size);
                return new SubList(this, offset, fromIndex, toIndex);
            }

            private void rangeCheck(int index) {
                if (index < 0 || index >= this.size)
                    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            }

            private void rangeCheckForAdd(int index) {
                if (index < 0 || index > this.size)
                    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            }

            private String outOfBoundsMsg(int index) {
                return "Index: "+index+", Size: "+this.size;
            }

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

        //和上面forEachRemaining基本一樣
        @Override
        public void forEach(Consumer<? super E> action) {
            //傳入函式介面不為空
            Objects.requireNonNull(action);
            //獲取當前list結構更改次數
            final int expectedModCount = modCount;
            //獲取當前陣列elementData
            @SuppressWarnings("unchecked")
            final E[] elementData = (E[]) this.elementData;
            //獲取當前ArrayList中元素個數
            final int size = this.size;
            //對每一個元素執行函式介面定義的操作
            for (int i=0; modCount == expectedModCount && i < size; i++) {
                action.accept(elementData[i]);
            }
            //結構改變異常檢查
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }

        /**建立一個延遲繫結,快速失效的迭代器Spliterator
         * @since 1.8
         */
        @Override
        public Spliterator<E> spliterator() {
            return new ArrayListSpliterator<>(this, 0, -1, 0);
        }


        //基於索引分成兩個延遲初始化分割器
        //ArrayList分割器,實現了分割器介面
        static final class ArrayListSpliterator<E> implements Spliterator<E> {

            /**
              * 如果ArrayList不可更改,or在結構不可變,我們可以用Arrays.spliterator來實現它們的分隔器.
              * 相反,我們在遍歷過程中檢測到的干擾與實際情況一樣多,不會犧牲太多效能
              * 我們主要依靠modcounts,但這並不能保證併發衝突,而且有時線上程衝突方面過於保守,但為了在實踐中檢測到足夠的問題這樣做是值得的.
              *
              * 為了做到這一點,
              * (1)延遲初始化fence,expectedModCount,直到我們需要提交到我們正在檢查的狀態的最後一點;從而提升準確度.(這
              * 並不適用於SubList,它在建立spliterator時,並未使用延遲載入策略)
              *
              * (2)我們只是在forEach方法的最後進行了併發異常檢查.當使用forEach時,我們在action後檢測異常,而並非之前.
              * 更深層次的CME觸發器適用於所有其它的違反假設的情況,例如:null或者給定由於併發導致size特別小的elementData,.
              * 這允許forEach在內部迴圈時,不再做更深層次的檢查,簡化了lambda表示式的action操作.
              * 雖然這需要進行多次檢查,但請注意,在list.stream().forEach()的常見情況下,除了forEach本身之外,不會執行任何檢查或其他計算.
              * 其它一些不常用的方法無法利用stream流提供的大多數優勢.
              */

            private final ArrayList<E> list;
            private int index; // current index, modified on advance/split當前索引,在前進,分割時發生值的更改.
            private int fence; // -1 until used; then one past last index,未使用前是-1
            private int expectedModCount; // initialized when fence set,當fence設定值時,為其初始化.

            /** Create new spliterator covering the given  range */
            //根據給定的索引範圍建立新的分割器.
            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;
            }

            //第一次使用時,為fence初始化
            private int getFence() {
                int hi; //forEach方法中,一個指定出現的變數.
                ArrayList<E> lst;
                //如果hi=fence<0
                if ((hi = fence) < 0) {
                    //如果list==null,則fence=0
                    if ((lst = list) == null)
                        hi = fence = 0;
                    //如果list!=null,則fence=list.size;  同時初始化expectedModCount
                    else {
                        expectedModCount = lst.modCount;
                        hi = fence = lst.size;
                    }
                }
                //返回fence
                return hi;
            }

            //嘗試獲取後面一半的分割器.
            public ArrayListSpliterator<E> trySplit() {
                //hi=fence
                //lo=index
                //mid=(hi+lo)/2
                int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
                //將分隔範圍一分為二;如果索引範圍太小,則不分割
                //如果分割,則返回的分割器範圍是:[lo,mid).
                return (lo >= mid) ? null : // divide range in half unless too small
                        new ArrayListSpliterator<E>(list, lo, index = mid,
                                expectedModCount);
            }

            /**
             * 利用傳入函式介面,對elementData[index]處理;
             * 處理成功:返回true;
             * 處理失敗:返回false;
             */
            public boolean tryAdvance(Consumer<? super E> action) {
                //判定函式介面是否為null
                if (action == null)
                    throw new NullPointerException();
                //前置索引i ,後置分割索引hi
                int hi = getFence(), i = index;
                //前置索引必須<後置索引,否則返回false
                if (i < hi) {
                    //前置索引+1
                    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;
            }

            //利用傳入函式介面,對elementData中每一個元素做處理.
            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;
                    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)
                            return;
                    }
                }
                throw new ConcurrentModificationException();
            }

            //預估分割器size
            public long estimateSize() {
                return (long) (getFence() - index);
            }

            //ArrayList的SplIterator一些屬性值
            public int characteristics() {
                return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
            }
        }

        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            Objects.requireNonNull(filter);
            //記錄刪除元素個數
            int removeCount = 0;
            //BitSet用每一位儲存一個true或者false值,通過set方法設定.
            //刪除元素位置設為true.
            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);
                    removeCount++;
                }
            }
            //併發異常檢查
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }

            // shift surviving elements left over the spaces left by removed elements
            final boolean anyToRemove = removeCount > 0;
            //如果有元素刪除,則對elementData陣列左移
            if (anyToRemove) {
                //新size大小
                final int newSize = size - removeCount;
                for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                    i = removeSet.nextClearBit(i);//返回值為false的索引,因為這樣索引位置處的值沒有刪除
                    elementData[j] = elementData[i];
                }
                //null設定,為GC準備
                for (int k=newSize; k < size; k++) {
                    elementData[k] = null;  // Let gc do its work
                }
                //更新size值
                this.size = newSize;
                //併發異常檢查
                if (modCount != expectedModCount) {
                    throw new ConcurrentModificationException();
                }
                //結構更改次數+1
                modCount++;
            }
            //返回true:如果有元素刪除;反之false
            return anyToRemove;
        }

        //利用傳入函式介面,更新elementData中每一個值
        @Override
        @SuppressWarnings("unchecked")
        pu