ArrayList源碼解析

學習源碼之前我們一定要弄明白三件事情:

  • 類的繼承結(jié)構(gòu) : 該類到底實現(xiàn)了什么接口,繼承了哪些類,甚至是使用了何種設(shè)計模式
  • 類的構(gòu)造函數(shù) : 通過嘞重載的構(gòu)造函數(shù)可以理清楚該類在初始化過程中干了什么事情
  • 類中常用方法: 觀察每個方法具體實現(xiàn)了那些職責
    tips: 根據(jù)阿里巴巴java開發(fā)手冊,public的方法應(yīng)該放在類的最上面,這也完全符合源碼的設(shè)計規(guī)范

簡介

ArrayList繼承樹圖:

image.png

add()方法

    public boolean add(E e) {
        //首次添加元素的時候,size為0
        ensureCapacityInternal(size + 1); 
       // 數(shù)組+1,填充元素
        elementData[size++] = e;
        return true;
    }

進入ensureCapacityInternal()方法

    // minCapacity:put進一個元素后,數(shù)組的實際長度
    private void ensureCapacityInternal(int minCapacity) {  
   // 這一步是判斷我們存放數(shù)據(jù)的數(shù)組elementData到底是不是為空
   // 記住這一步他和grow()方法的第三行代碼息息相關(guān)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
   // 判斷默認容量(10) 和這個數(shù)組實際長度誰大, 大的一邊就成為數(shù)組的實際長度
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
   //  
        ensureExplicitCapacity(minCapacity);
    }

進入ensureExplicitCapacity()方法

    private void ensureExplicitCapacity(int minCapacity) {
    // 這個變量用于記錄修改次數(shù),用于在并發(fā)時拋出異常使用
        modCount++;
    // 如果現(xiàn)在的實際長度要大于數(shù)組的長度了, 那么就表示要進行擴容操作了
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

進入grow()方法

    private void grow(int minCapacity) {
        
        int oldCapacity = elementData.length;
       // 最核心的重點來了  可以看出來ArrayList時擴容為原來的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
      // 如果是使用默認構(gòu)造器并且是首次add的話,那么上面計算的newCapacity一定是0
      //  minCapacity的值根據(jù)ensureCapacityInternal()方法第一行的判斷它的值是10
     //  其實這里就是驗證ArrayList初始容量大小為10的地方
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
    // 這里就是判斷是不是大數(shù)組了 詳細的就不看了
        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的擴容機制了。首先創(chuàng)建一個空數(shù)組elementData,第一次插入數(shù)據(jù)時直接擴充至10,然后如果elementData的長度不足,就擴充至1.5倍,如果擴充完還不夠,就使用適合的長度作為elementData的長度。

構(gòu)造器的選擇

那么既然ArrayList會進行頻繁的判斷以及擴容操作,那么我們遇到\color{red}{大數(shù)據(jù)批量插入}的情況應(yīng)該怎么應(yīng)對呢

  • 使用ArrayList(int initialCapacity)這個有參構(gòu)造函數(shù),在創(chuàng)建時就聲明一個較大的大小,這樣解決了頻繁拷貝問題,但是需要我們提前預(yù)知數(shù)據(jù)的數(shù)量級,也會一直占有較大的內(nèi)存。
  • 我們可以初始化的時候手動調(diào)用一次ensureCapacity(int capacity)方法,也能達到提高效率的目的
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容