ArrayList源碼分析及擴容機制

ArrayList的主要成員變量:

//數組默認初始容量
private static final int DEFAULT_CAPACITY = 10;

//定義一個空的數組實例以供其他需要用到空數組的地方調用 
private static final Object[] EMPTY_ELEMENTDATA = {};
 
/*
定義一個空數組,跟前面的區別就是這個空數組是用來判斷ArrayList第一添加數據的時候要擴容多少。
默認的構造器情況下返回這個空數組 
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 
/*
數據存的地方它的容量就是這個數組的長度,同時只要是使用默認構造器:
(DEFAULTCAPACITY_EMPTY_ELEMENTDATA )第一次添加數據的時候容量擴容爲DEFAULT_CAPACITY = 10 
*/
transient Object[] elementData;
 
private int size;//當前數組的長度

部分源碼分析:

	//序列號
	private static final long serialVersionUID = 8683452581122892189L;
 	//默認容量
    private static final int DEFAULT_CAPACITY = 10;
 
    /**
     * 一個空數組
     * - 當用戶指定該 ArrayList 容量爲 0 時,返回該空數組
     * - ArrayList(int initialCapacity)
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};
 
    /**
     * 一個空數組實例
     * - 當用戶沒有指定 ArrayList 的容量時(即調用無參構造函數),返回的是該數組==>剛創建一個 ArrayList 時,其內數據量爲 0。
     * - 當用戶第一次添加元素時,該數組將會擴容,變成默認容量爲 10(DEFAULT_CAPACITY) 的一個數組
     * ===>通過  ensureCapacityInternal() 實現
     * 它與 EMPTY_ELEMENTDATA 的區別就是:該數組是默認返回的,而後者是在用戶指定容量爲 0 時返回
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 
    /**
     * ArrayList基於數組實現,用該數組保存數據, ArrayList 的容量就是該數組的長度
     * - 該值爲 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 時,當第一次添加元素進入 ArrayList 中時,數組將擴容值 DEFAULT_CAPACITY(10)
     */
    transient Object[] elementData; // non-private to simplify nested class access
 
    /**
     * ArrayList實際存儲的數據數量
     */
    private int size;
    
    /**
     * 創建一個初試容量的、空的ArrayList
     * - 可能報錯: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
     * @param  initialCapacity  初始容量
     * @throws IllegalArgumentException 當初試容量值非法(小於0)時拋出
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
        	// 數組緩衝區爲 EMPTY_ELEMENTDATA,注意與 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的區別
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }

    /**
     * 無參構造函數:
     * - 創建一個 空的 ArrayList,此時其內數組緩衝區 elementData = {}, 長度爲 0
     * - 當元素第一次被加入時,擴容至默認容量 10
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

擴容機制:

    /**
     * 添加新值到 list 末尾
     * @param e 添加的值
     * @return <tt>true</tt>
     */
    public boolean add(E e) {
    	// 確定ArrayList的容量大小---嚴謹
    	// 注意:size + 1,保證資源空間不被浪費,按當前情況,保證要存多少個元素,就只分配多少空間資源
        ensureCapacityInternal(size + 1);  // 這裏是size是指已經有幾個元素,如果是初次add,size爲0
        // 添加 e 到 ArrayList 中,然後 size 自增 1
        elementData[size++] = e;
        return true;
    }
	/**
     * 指定 ArrayList 的容量
     * @param   minCapacity   指定的最小容量
     */
    public void ensureCapacity(int minCapacity) {
    	// 最小擴充容量,默認是 10
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
        
        // 若用戶指定的最小容量 > 最小擴充容量,則以用戶指定的爲準,否則還是 10
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);	
        }
    }
    
    /**
     * 私有方法:明確 ArrarList 的容量,提供給本類使用的方法
     * - 用於內部優化,保證空間資源不被浪費:尤其在 add() 方法添加時起效
     * @param minCapacity    指定的最小容量
     */
    private void ensureCapacityInternal(int minCapacity) {
        //第一次添加,調用add()時,elementData == {}
    	// 若 elementData == {},則取 minCapacity 爲 默認容量和參數 minCapacity 之間的最大值
    	//假設第一次添加,調用add(),minCapacity爲0,默認容量爲10,則取DEFAULT_CAPACITY默認容量的值,即爲10
    	// 注:ensureCapacity() 是提供給用戶使用的方法,在 ArrayList 的實現中並沒有使用
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);	
    }
    
    /**
     * 私有方法:明確 ArrayList 的容量
     * - 用於內部優化,保證空間資源不被浪費:尤其在 add() 方法添加時起效
     * @param minCapacity    指定的最小容量
     */
    private void ensureExplicitCapacity(int minCapacity) {
    	// 將“修改統計數”+1,該變量主要是用來實現fail-fast機制的 
        modCount++;
 
        // 防止溢出代碼:確保指定的最小容量 > 數組緩衝區當前的長度
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    /**
     * 私有方法:擴容,以確保 ArrayList 至少能存儲 minCapacity 個元素
     * - 擴容計算:newCapacity = oldCapacity + (oldCapacity >> 1);	
     * @param minCapacity    指定的最小容量
     */
    private void grow(int minCapacity) {
    	// 防止溢出代碼
        int oldCapacity = elementData.length;
        // 運算符 >> 是帶符號右移. 如 oldCapacity = 10,則 newCapacity = 10 + (10 >> 1) = 10 + 5 = 15
        int newCapacity = oldCapacity + (oldCapacity >> 1);	
        if (newCapacity - minCapacity < 0)					// 若 newCapacity 依舊小於 minCapacity
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)			// 若 newCapacity 大於最大存儲容量,則進行大容量分配
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章