關於ArrayList的源碼關注點
1.從底層數據結構,擴容策略
2.ArrayList的增刪改查
3.特殊處理重點關注
4.遍歷的速度,隨機訪問和iterator訪問效率對比
1.從底層數據結構,擴容策略
對於第一個問題,底層即時一個object的數組,用來存放動態數據:
transient Object[] elementData;
默認初始容量大小是10個,注意這裏有個坑不是一開始就是10個,而是當進行add操作的時候,會默認修改爲10個:private static final int DEFAULT_CAPACITY = 10;
源碼中進行初始化的時候:

而我們的DEFAULTCAPACITY_EMPTY_ELEMENTDATA這個數據是,也就是說只進行new操作的時候,我們是給了一個空的數組大小是0長度是0,大小是0
Private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
這裏源碼中有一段代碼:
collection.toArray()應該等同於collection.toArray(new Object[0]),返回的是Object[]類型。然而,Arrays.asList卻不是這樣,如果它的類型是一個Object[]子類(比如String[]),那麼toArray()就會返回這個子類而不是Object[],因為它調用的是clone())
作者:楊寒
鏈接:https://www.zhihu.com/question/26603565/answer/33394672
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
EnsureCapacityInternal 擴容策略最終調用======》grow方法進行大小增長
只有在容量不夠了的時候纔會採取擴容措施
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); 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); }
1.而且擴容也很簡單粗暴,直接擴大1.5倍,採用右移的方式進行擴容,然後加上原始容量
2.如果括了1.5倍,還是比需要獲取的大小要小,那麼就直接把大小擴爲想要獲取的大小
3.如果擴容之後的大小,超出限制(Integer.MAX_VALUE - 8;),那麼就擴到最大Integer.MAX_VALUE,如果期望的大小還沒超過這個Integer.MAX_VALUE - 8;那麼就擴圍Integer.MAX_VALUE - 8;
最後吧新的數據拷貝過來取代舊數據
2.ArrayList的增刪改查
2.1 add操作
進行add操作的時候支持2種添加方式
添加的時候size+1,作爲新的size,然後調用擴容策略
最後吧新數據放到最後一個位置,返回true
其次添加到指定位置
做了2次拷貝操作
1.先創建新的容納大小的空間
2.然後把需要添加進去的數據的index位置,往後推移拷貝一遍,然後再指定位置寫入
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
2.2 刪除remove(obj),remove(int),fastRemove
Remove(obj)刪除操作底層調用的還是fastremove
根據要刪除的位置計算需要移動的元素個數
比如2個元素,現在要刪除第一個元素,那麼index=0,那麼就是2-0-1 = 1;需要移動一個
Index就是對應的元素的下標,numMoved就是需要移動的元素的個數
直接刪除索引
Remove(int)
刪除這個索引之前,會先判斷是否越界
和之前的刪除大同小異
修改,查詢就不說了,就是set和get操作,分別是elementData[index] = ele,和return elemenetData[index]
3.特殊處理重點關注,iterator
1.這裏注意ArrayList有一個modCount屬性,這個屬性用來標識這個list被修改了多少次
2.注意使用迭代器的時候,對元素的增加或者刪除,請用迭代器的刪除,而不能用list的remove,而且遍歷的時候只能刪除,不能做新增
這個方法會校驗
ExpectedModCount 而這個參數在創建iterator的時候,就進行了賦值 int expectedModCount = modCount;
4.遍歷的速度,隨機訪問和iterator訪問效率對比
並沒有差別,其實iterator也就是對數組訪問,所以不存在效率問題,只是我們一般的情況可以進行隨機訪問,而iterator只能進行遍歷
5.是否支持多線程
這個就否了,不用管
借鑑:
https://www.zhihu.com/question/26603565
https://blog.csdn.net/fighterandknight/article/details/61240861