ArrayList源碼閱讀

ArrayList源碼閱讀筆記

內部屬性

    //默認容量
    private static final int DEFAULT_CAPACITY = 10;
    //對於已知大小爲0 的 返回此空數組
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //默認容量DEFAULT_CAPACITY的空數組 , 暫時實際爲0 的空數組 ,初次執行add方法時,會擴容爲DEFAULT_CAPACITY
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //存放數據的數組的緩存變量,不可序列化
    transient Object[] elementData;
    //元素數量
    private int size;
    //父級AbstractList的成員屬性:用於記錄集合結構變化次數(擴容、刪除、新增等所有會改變集合長度的操作)
    protected transient int modCount = 0;

構造方法

1、public ArrayList(int initialCapacity) :
	根據給定大小,初始化elementData  ;
	如果大小爲0 ,設置 elementData =  EMPTY_ELEMENTDATA 空數組
2、public ArrayList() :
	設置 elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA空數組,
	初次執行add()時會被擴容爲默認大小
3、public ArrayList(Collection<? extends E> c) :
	c不能爲null,c長度爲0 ,設置elementData = EMPTY_ELEMENTDATA 空數組 ,
	否則elementData 長度爲c的大小

增刪改查

add : 新增
    1、如果是指定索引新增:檢查索引 rangeCheckForAdd(int index) 
    2、判斷是否需要擴容 (當前集合元素個數+1,作爲最小參數)
    3、添加元素
set : 修改
    1、檢查索引 rangeCheck(index);
    2、修改
remove: 刪除
    1、根據索引刪除 : 檢查索引 rangeCheck(index);
    2、刪除
get : 查看
    1、檢查索引 rangeCheck(index);
    2、返回元素

擴容機制

1、根據當前集合實際元素siez + 1 作爲集合需要的最小容量值,判斷是否需要擴容 【應爲只有add 纔會有擴容,所以需要用size+1判斷本次新增是否需要擴容】
2、 ensureCapacityInternal:確定內部需要容量最小值 
    private void ensureCapacityInternal(int minCapacity) {
        //初次執行add 無參構造容量設置爲默認容量
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
3、:ensureExplicitCapacity-確保容量
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        //所需最小容量 大於 當前elementData長度 執行擴容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
4、執行擴容:
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        // 擴容 1.5倍  
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)  //擴容1.5倍後,新容量 小於 所需最小容量 ,使用最小容量爲擴容後大小 
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0) //擴容1.5倍後,新容量超過數組支持的最大容量值,使用最大值
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);//拷貝數據到一個新的容量大小的數組中
    }

遍歷

foreach 使用了modCount結構變化次數驗證,遍歷過程中改變size操作會報ConcurrentModificationException

    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

Iterator:內部類Itr迭代器 remove方法顯示的設置modCount跟操作後相等,所以支持迭代過程中修改

private class Itr implements Iterator<E> {
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

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

序列化 序列化後的流中記錄了集合結構變化次數,所以讀操作後在修改,也會發現

讀 :readObject

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // 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();
            }
        }
    }

寫 :writeObject

    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();
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章