JDK1.8源碼閱讀---ArrayList

一、簡介

   ArrayList是基於數組實現的一個動態數組,其容量能自動增長。ArrayList不是線程安全的,多線程環境下考慮Collections.synchronizedList(List l)函數返回一個線程安全的ArrayList類,也可以使用concurrent併發包下的CopyOnWriteArrayList類。

二、源碼理解

2.1 類繼承關係

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList繼承AbstractList抽象父類,實現了List接口(規定了List的操作規範)、RandomAccess(可隨機訪問)、Cloneable(可拷貝)、Serializable(可序列化)

2.2 類屬性

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;
    //空實例,默認爲{},通過帶參數構造器創建實例時使用
    static final Object[] EMPTY_ELEMENTDATA = {};
    //缺省空實例,採用ArrayList默認大小10創建的空實例
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //用來存儲真正的數據數組
    transient Object[] elementData; 
    //數組元素數量
    private int size;
    //最大數組容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}

2.3 構造函數

  1. 有參構造器(初始化數組容量)

     public ArrayList(int initialCapacity) {
     		//如果initialCapacity大於0則根據指定的大小創造一個數組
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            //如果initialCapacity等於0則將默認的空列表EMPTY_ELEMENTDATA賦值給elementData
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
           //小於0則拋出參數異常
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
            }
        }
    
  2. 無參構造器

     public ArrayList() {
     		//將DEFAULTCAPACITY_EMPTY_ELEMENTDATA空數組賦值給elementData
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
  3. 有參構造器(根據給定的集合)

    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
           //如果elementData長度不等於0,並且不是Object類型數組時,則調用Arrays.copyOf複製一個Object類型數組,並複製給elementData
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //如果數組大小等於0,則將EMPTY_ELEMENTDATA空數組賦值給elementData 
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
    

2.4 核心函數

  • add(E e):添加元素

    public boolean add(E e) {
    		//調用ensureCapacityInternal函數,確定數組的大小,size+1表示添加當前元素後數組的容量大小
            ensureCapacityInternal(size + 1); 
            //將數組size位置的元素設置爲e
            elementData[size++] = e;
            return true;
        }
    
    private void ensureCapacityInternal(int minCapacity) {
    	//如果數組是默認的空數組,則將minCapacity與默認數組的容量大小比較,取最大的賦值給minCapacity(需要的數組容量值)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    	//確定是否需要數組擴容
        ensureExplicitCapacity(minCapacity);
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
           //記錄集合的修改次數
            modCount++;
    		//如果需要的數組容量大小大於當前數組大小,則調用grow()方法進行擴容
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
    //這個方法是ArrayList這個類add方法的最後一步,主要做的就是確定size然後進行數組的copy與賦值
    //至於真正的copy,是由Arrays.copyOf調用System.arraycopy,最後完成copy這一步是個native方法去做的
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //newCapacity當前數組容量,取原數組的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果暫定數組容量不滿足指定容量minCapacity,則將minCapacity賦值給newCapacity
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //如果newCapacity大於最大容量,則調用hugeCapacity()方法確定最終值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //調用Arrays.copyOf(原數組,數組大小),將數組copy形成新的數組重新複製,從而完成數組的擴容
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
    //超容量數組大小判斷
    private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            //如果minCapacity 大於MAX_ARRAY_SIZE則取Integer的最大值,如果小於則取MAX_ARRAY_SIZE
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
    

    通過add方法的閱讀可以發現,幾個重要的點

    • ArrayList本質上是個數組,數據存儲是由數組來完成,ArrayList只不過是進行了封裝、擴展功能
    • 數組容量最大爲Integer的最大值
    • 添加元素內部實現,其實是建立的新的數組,所以再創建ArrayList時最好有個預估容量大小,不然會造成頻繁的擴容
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章