面試中經常問到的問題之一就是List的擴容機制了,他是怎么做到擴容的,大家都能答出來底層是數組,復制一個數組來擴容,但是再具體一點來說,大家就不知道該怎么說了,如果不看源碼說這么多確實就差不多了,但是看了源碼你會說的更多,更詳細,更具體,本篇主要看的是jdk1.8 至於其他版本大同小異,看看就知道了,言歸正傳
1)List擴容實現步驟
總的來說就是分兩步:1、擴容
把原來的數組復制到另一個內存空間更大的數組中
2、添加元素
把新元素添加到擴容以后的數組中
2)源碼分析
先把ArrayList中定義的一些屬性貼出來方便下面源碼分析
分析之前我們先看一下ArrayList的兩個構造方法
ArrayList()
ArrayList(int initialCapacity)
01
|
無參構造:
|
01
02
03
04
05
|
public
ArrayList() {
this
.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
帶參構造:
|
01
02
03
04
05
06
07
08
09
10
|
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);
}
}
|
在無參構造中,我們看到了在用無參構造來創建對象的時候其實就是創建了一個空數組,長度為0
在有參構造中,傳入的參數是正整數就按照傳入的參數來確定創建數組的大小,否則異常
接下來我們來看擴容,擴容的方法就是 add(E e)
貼上源碼
看,其實add方法就兩步,第一步:增加長度,第二步:添加元素到數組,第二步沒什么說的,我們看看ensureCapacityInternal(int minCapacity)這個增加長度的方法
這個地方我們看到了,如果在添加的時候遠數組是空的,就直接給一個10的長度,否則的話就加一
if (minCapacity - elementData.length > 0) grow(minCapacity);
通過這個地方是真正的增加長度,當需要的長度大於原來數組長度的時候就需要擴容了,相反的則不需要擴容
這個地方注意這一句
int newCapacity = oldCapacity + (oldCapacity >> 1);
oldCapacity >> 1 右移運算符 原來長度的一半 再加上原長度也就是每次擴容是原來的1.5倍
之前的所有都是確定新數組的長度,確定之后就是把老數組copy到新數組中,這樣數組的擴容就結束了
以上的一切都是ArrayList擴容的第一步,第二步就沒啥說的了,就是把需要添加的元素添加到數組的最后一位