【數據結構】1.java源碼ArrayList

 關於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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章