Java源碼閱讀系列(一)-ArrayList源碼閱讀

ArrayList源碼分析

1、增加元素

ArrayList有兩個不同的add()方法。常用的就是第一個,添加元素到list的末尾,只分析第一個方法。

/**
     * 將指定的元素添加到列表末尾.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        //確認List容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //把元素放到List的末尾
        elementData[size++] = e;
        return true;
    }

來看ensureCapacityInternal(size + 1); // Increments modCount!!

執(zhí)行的是以下方法,size是當前ArrayList的大小0:

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));  //calculateCapacity執(zhí)行的是下面的靜態(tài)方法calculateCapacity
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
} 

calculateCapacity方法中對elementData進行檢查,如果它是DEFAULTCAPACITY_EMPTY_ELEMENTDATA的,就返回size和DEFAULT_CAPACITY兩者中的最大值,第一次添加元素時,擴容到默認值10。

調用無參構造的時候,把DEFAULTCAPACITY_EMPTY_ELEMENTDATA賦值給了 elementData,此時一定是它。

/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

DEFAULT_CAPACITY默認為10.

/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;

源碼中對elementData的注釋寫的很清楚,如果 一個ArrayListelementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么在第一次添加元素時就擴容為默認容量10.

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

下面這一步就是很重要的擴容了,calculateCapacity返回ArrayList的大小之后,執(zhí)行ensureExplicitCapacity,modCount++,然后判斷元素的lengthminCapacity的大小,在第一次增加元素的時候,會進入grow

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

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

擴充:

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
private void grow(int minCapacity) {
    // 獲取當前數(shù)組容量
    int oldCapacity = elementData.length;
    //擴容,新數(shù)組容量 = 當前數(shù)組容量 + 當前數(shù)組容量/2
    //右移除以2的幾次冪,左移乘以2的幾次冪
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果擴充之后的容量還小于想要的容量,擴充容量就等于想要的容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //拿擴充之后的容量和臨界值比較,如果大于臨界值,進行大容量分配
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

大容量分配:

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    //判斷想要的是否大于臨界值,如果大于,則返回Integer.MAX_VALUE(0x7fffffff),否則返回MAX_ARRAY_SIZE
    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

MAX_ARRAY_SIZE為什么要-8

因為某些VM會在數(shù)組中保留一些頭字,嘗試分配這個最大存儲容量,可能會導致Array容量大于VMlimit,最終導致OutOfMemoryError

/**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

然后增加的過程就完事了。

未完待續(xù)。。。
很快!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容