ArrayList的擴容機制以及常用方法源碼分析

一直想記錄自己的學習過程,但始終沒有付出實際行動,說來慚愧

感謝您的關注,持續更新,歡迎留言交流~

前言:

雖然面試我們通常是講ArrayList和數組的區別,但小編覺得,我們有必要去了解一下ArrayList,在我們日常開發上,ArrayList也算得上是一種常用的集合了,接下來就和小編一起來扯下淡吧~

話不多說,直接上源碼,以下源碼基於JDK1.8 讓我們先來看看 

ArrayList list = new ArrayList();
list.add("小編是個禿頂的大叔~");
    // 默認爲 0
    private int size;

    /**
     * Appends the specified element to the end of this 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) {
        // size[0] + 1 當作參數傳入方法 
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }

接下來我們來看看ensureCapacityInternal()方法

思路:其實就是判斷數組是否初始化,未初始化賦初始值 10 

    // transient是用來反序列化的
    transient Object[] elementData; 

    // 定義一個空數組
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    // 默認容量爲 10
    private static final int DEFAULT_CAPACITY = 10;

    /**
    * minCapacity:當前存放值的下標 + 1(size + 1) 
    */
    private void ensureCapacityInternal(int minCapacity) {
        // 判斷elementData是不是默認的空數組
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 取得兩個參數中的最大值:DEFAULT_CAPACITY --> 10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        // minCapacity = 10
        ensureExplicitCapacity(minCapacity);
    }

接下來我們看看ensureExplicitCapacity()方法:

擴容的大致整體思路:

1.判斷這個集合是否達到擴容的標準

2.若擴容之後的長度比插入的這個當前的容量還小,則擴容的容量 = 當前容量(minCapaccity)

3.如果擴容的大小比ArrayList的最大長度還大  如何處理【hugeCapacity方法】

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//modCount是記錄修改次數 與線程安全有關係

        // 判斷是否達到擴容的條件: 當前容量 > 數組長度
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // 賦值以前的容量
        int oldCapacity = elementData.length;

        // 當前容量爲:old容量 + (old容量 / 2) 對於>>不懂的,小編後邊會專門寫一篇博客
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        // 擴容後的容量 小於 當前容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;

        // 擴容後的容量 大於 arraylist最大容量時
        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);
    }

// 小編覺得很有必要講一下這個方法:擴容之後大於ArrayList的最大容量執行的hugeCapacity方法

有這麼幾個疑問:

1.爲什麼ArrayList的最大數組大小(MAX_ARRAY_SIZE)是:Integer.MAX_VALUE - 8?

2.爲什麼Integer.MAX_VALUE用0x7fffffff表示?

3.如果當前容量 大於 最大容量則賦值數組長度爲Integer.MAX_VALUE,明明已經大於最大容量了?

    /**
     * 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;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    @Native public static final int   MAX_VALUE = 0x7fffffff;

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

第一個問題:ArrayList的最大數組大小爲什麼是Integer.MAX_VALUE - 8?

剛開始小編也是到處找資料說是數組需要8 bytes去存儲它自己的大小,開始小編覺得這個回答有些敷衍,直到用翻譯工具截圖翻譯,這才解釋了源碼上這段可惡的英文,偶買噶,無形之中就暴露了小編的英文水平,請替我保密~~,哈哈哈哈哈哈

第二個問題:Integer.MAX_VALUE 爲什麼用0x7fffffff代表?

ox代表是16進制 7fffffff纔是16進制的值,簡單的說就是方便運算,計算器能理解的東西,我們不一定能理解。詳細可自行Google一下或找本基礎教材翻一下。

第三個問題:Integer.MAX_VALUE就是一個最大最大的上線,再大也不能比天王老子Integer的最大值大

關注小編,點個贊留個評論也是對小編莫大的支持,謝謝帥鍋

後面持續更新,地中海髮型尚未形成,小編仍需努力。。。。

發佈了3 篇原創文章 · 獲贊 28 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章