ArrayList
- 構造函數
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
我們先來看構造函數,ArrayList.java裏面有幾個變量,
final MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
設置最大數組大小,其中 Integer.MAX_VALUE
爲 java 中 int最大值 爲的 2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647,所以這裏的值爲 2147489647 - 8=214748363 9;
final DEFAULT_CAPACITY = 10
默認大小爲10
final Object[] EMPTY_ELEMENTDATA = {}
設置一個空的object對象數組
transient Object[] elementData
聲明一個新的 Object 不被序列化的數組,這個數組是主要數組,所有的元素都將放在這個數組裏面
當我們調用無參的構造函數時,初始化當前elementData
爲EMPTY_ELEMENTDATA
,即爲空。
當我們調用有初始化大小的構造函數時,判斷initialCapacity
是否大於零,大於則初始化一個大小爲
initialCapacity
的Object對象數組。等於零則初始化當前elementData
爲EMPTY_ELEMENTDATA
,即爲空
當小於零,拋出錯誤
當我們調用參數爲集合的構造函數時,此構造函數的意思是將集合轉爲ArrayList,
先將 參數轉爲數組並賦給elementData
,判斷當elementData
長度不爲零時,判斷是否成功將參數集合轉化爲Object類型的數組,如果轉化成Object類型的數組成功,則將數組進行復制,轉化爲Object類型的數組。
當 elementData
長度爲零時,則初始化當前elementData
爲EMPTY_ELEMENTDATA
,即爲空。
- 擴容
public boolean add(E e) {
ensureCapacityInternal(size + 1); //擴容
...
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判斷是否爲空,爲空則返回初始值和設置值中最大的部分
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;//否則返回設置值
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//記錄修改次數
// overflow-conscious code
if (minCapacity - elementData.length > 0)//判斷大小是否大於當前list對象的長度
grow(minCapacity);//長度增加
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//未增加前長度
int newCapacity = oldCapacity + (oldCapacity >> 1);//位運算,讓長度增加原來的1.5倍
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();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
//當長度大於最大長度,則返回int類最大值,否則返回最大長度
//源碼上有寫最大長度=int類最大值-8
}
擴容函數爲add()
函數調用,函數主體是ensureCapacityInternal
,參數爲未擴容前大小+1,
調用 ensureCapacityInternal(int minCapacity)
函數後,
再調用 calculateCapacity(Object[] elementData, int minCapacity)
,這個函數有兩個參數,一個是當前elementData,一個是擴容後的大小 ,這個函數的作用是,判斷elementData
是否爲空,如果是,則返回默認大小和擴容後大小的最大值,如果不爲空,則直接返回擴容後的大小
然後調用ensureExplicitCapacity()
這個函數的參數是 校驗後的 minCapacity
,這個函數的作用是,開始先將修改步驟++,即 modCount++
,然後執行grow()
進行擴容,
minCapacity
表示集合爲了確保添加元素成功的最小容量。在擴容的時候,首先將原元素數組的長度增大1.5倍(oldCapacity + (oldCapacity >> 1))
,然後對擴容後的容量與minCapacity
進行比較:① 新容量小於minCapacity
,則將新容量設爲minCapacity
;②新容量大於minCapacity
,則指定新容量。最後將舊數組拷貝到擴容後的新數組中。
資料:
copyOf詳解
modCount
transient