學習源碼之前我們一定要弄明白三件事情:
- 類的繼承結(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會進行頻繁的判斷以及擴容操作,那么我們遇到的情況應(yīng)該怎么應(yīng)對呢
- 使用ArrayList(int initialCapacity)這個有參構(gòu)造函數(shù),在創(chuàng)建時就聲明一個較大的大小,這樣解決了頻繁拷貝問題,但是需要我們提前預(yù)知數(shù)據(jù)的數(shù)量級,也會一直占有較大的內(nèi)存。
- 我們可以初始化的時候手動調(diào)用一次ensureCapacity(int capacity)方法,也能達到提高效率的目的