一、源碼如何分析?
1.成員變量
2.構造方法
3.關鍵方法
? ? ? ? 一些添加的方法。
二、debug看源碼
我們給出下面代碼:
public void test01() {ArrayList<Integer> list = new ArrayList<>();list.add(1);for (int i = 2; i <= 10; i++) {list.add(i);}list.add(11);}
1.第一次添加數據
1. 添加方法:
2. 確保內部容量:
3. 計算容量:
4. 確保真正的容量:
5. 擴容的方法:
圍繞著這5個方法進行講解:
? ? ? ? 首先,add()方法里面先執行ensureCapacityInternal(size + 1); 這里的size是0,因為數組是空的,所以傳入到ensureCapacityInternal()方法的參數就是minCapacity?==?1 。
? ? ? ? 其次,我們就需要計算容量,在calculateCapacity()方法中,里面的傳入的兩個參數,其中第一個參數elementData的值,在ArrayList() 構造方法里面已經賦過值了,就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,第二個參數就是前面的 1 。所以if里面判斷正確,返回最大值,其中DEFAULT_CAPACITY = 10,所以10>1,最后返回的也就是10。
? ? ? ? 然后,我們在ensureExplicitCapacity()中這個方法,傳入的minCapacity這個參數也就是 10。因為在if判斷中,條件成立,也就是說容量不夠,需要擴容了。
? ? ? ? 最后,進入grow()方法,其中因為oldCapacity=0,newCapacity計算得出也是0。第一個條件判斷就是0-10<0,所以把10賦值給newCapacity,第二個是數組容量最大的安全校驗(暫時不用),最后一行代碼也就是數組的拷貝,把elementData的容量變成了 10 。
? ? ? ? 這樣,我們的數組第一次擴容就這樣說完了,我們回到add方法,elementData[size++] = e,這行代碼就是把下標為0的位置給了元素1,然后size+1,說明數組有一個元素了。
2.第二次添加數據
? ? ? ? 我們第二次添加是用for循環,添加了9個元素,我們分析這個過程。
? ? ? ? 首先,for循環添加第一個元素的時候,ensureCapacityInternal(size + 1); 這里的size是1,因為數組之前添加了一個元素進行了size++,所以傳入到ensureCapacityInternal()方法的參數就是minCapacity?== 2。
? ? ? ? 其次,在計算容量的時候,elementData已經不是默認的了,所以直接返回minCapacity。
? ? ? ? 然后,我們在ensureExplicitCapacity()中這個方法里面,在if判斷里面,其中minCapacity是等于2的,elementData.length在第一次添加數據的時候,已經擴容為10了,所以2-10<0,不需要擴容了。在代碼里面,for循環添加了9個元素,執行流程都一樣。
? ? ? ? 最后,在add方法里面,把數據添加到數組后進行size+1。
3.第三次添加數據
????????我們第三次添加一個元素,其中數組已經有10個元素了,我們分析這個過程。
????????首先,ensureCapacityInternal(size + 1); 這里的size是10,因為數組里面有了10個元素,所以傳入到ensureCapacityInternal()方法的參數就是minCapacity?== 11。
????????其次,在計算容量的時候,elementData已經不是默認的了,所以直接返回minCapacity。
????????然后,我們在ensureExplicitCapacity()中這個方法,傳入的minCapacity這個參數也就是 11。因為在if判斷中,條件成立11-10>0,也就是說容量不夠,需要擴容了。
????????最后,進入grow()方法,其中因為oldCapacity=10,?oldCapacity >> 1也就是右移一位也就是5,newCapacity計算得出是15。第一個條件判斷就是15-10>0,直接走過該判斷,最后一行代碼也就是數組的拷貝,把elementData的容量變成了 15 。
???????? 這樣,我們的數組擴容就完成了。
三、面試題
1. ArrayList底層的實現原理是什么?
-
底層數據結構
ArrayList底層是用動態的數組實現的
-
初始容量
ArrayList初始容量為0,當第一次添加數據的時候才會初始化容量為10
-
擴容邏輯
ArrayList在進行擴容的時候是原來容量的1.5倍,每次擴容都需要拷貝數組
-
添加邏輯
-
確保數組已使用長度(size)加1之后足夠存下下一個數據
-
計算數組的容量,如果當前數組已使用長度+1后的大于當前的數組長度,則調用grow方法擴容(原來的1.5倍)
-
確保新增的數據有地方存儲之后,則將新元素添加到位于size的位置上。
-
返回添加成功布爾值。
-
2.? ArrayList list=new ArrayList(10)中的list擴容幾次?
該語句只是聲明和實例了一個 ArrayList,指定了容量為 10,未擴容。