前面已經寫了三篇關於Java集合的文章,包括:
關於Vector,它的實現和ArrayList非常類似,就不再單開一個章節來講了,現在我們來對Java集合做一個歸納總結。
一. List框架圖
首先上面的框架圖可以表明順序的關聯關係,但並不全面,如ArrayList在繼承了AbstractList抽象類的同時還實現了List介面。
- List是一個介面,繼承了Collection,同時Collection繼承了Iterable,表明List的實現類都是可用迭代遍歷的;
- AbstractList是一個抽象類,實現了List介面,同時繼承了AbstractCollection,針對一些常用方法,如add(),set(),remove(),給了預設實現,當然在具體的實現類中基本都重寫了,該類中沒有get(),size()方法。
- AbstractSequentialList是一個抽象類,繼承了AbstractList抽象類,實現了很多雙向連結串列中根據索引操作的方法。
- ArrayList、Vector、LinkedList、Stack都是具體的實現類。
二. ArrayList、Vector對比分析
型別 | 執行緒安全 | 內部結構 | 擴容規則 | 執行效率 | 序列化 | |
---|---|---|---|---|---|---|
ArrayList | 否 | 陣列Object[] | 10 | 陣列足夠最小長度*1.5 | 高 | 是 |
Vector | 是 | 陣列Object[] | 10 | 預設陣列足夠最小長度*2,可自定義每次擴容數量 | 低 | 是 |
Vertor擴容方法:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//capacityIncrement引數可通過建構函式傳遞進來,若沒傳遞該引數,則陣列大小設定為elementData.length * 2
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//擴容有上限
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
三. ArrayList、LinkedList對比分析
型別 | 內部結構 | 插入效率(正常情況) | 刪除效率(正常情況) | 順序遍歷效率 | 隨機遍歷效率 | 佔用記憶體 | 序列化 |
---|---|---|---|---|---|---|---|
ArrayList | 陣列Object[] | 低 | 低 | 高 | 高 | 低 | 是 |
LinkedList | 雙向連結串列Node | 高 | 高 | 高 | 低 | 高 | 是 |
上述的對比都是基於大資料量的情況下,如果只是幾個元素或幾十個元素,它們之間並沒有多大區別。
問:插入效率為何說正常情況下ArrayList低,LinkedList高呢?
答:我們清楚ArrayList之所以插入效率低,有兩個原因會造成時間的消耗。
第一,當底層陣列空間不足時需要擴容,擴容後需進行陣列拷貝
第二,當不在陣列末尾插入資料,那麼就需要移動陣列元素
知道了其插入效率低的原因後,那麼很明顯,資料擴容及拷貝只有在陣列空間不足時才發生,如果我們正確使用,就像《阿里巴巴Java開發手冊》中提到我們在建立集合物件時,就傳遞引數預先設定好陣列大小,那麼插入效率是非常高的;而90%的情況下我們在新增元素時都呼叫的是add(E e),直接在末尾新增元素,很少呼叫add(int index, E e)在陣列中部新增元素,這樣其實移動陣列元素就很少發生,因此插入效率也很高。
問:刪除效率為何說正常情況下ArrayList低,LinkedList高呢?
答:因為刪除效率高、低不是絕對的。其實刪除操作可以分為兩部分。
第一:找到要刪除的元素,這個通過索引找,ArrayList的執行效率要遠高於LinkedList的執行效率;通過equals找則需要遍歷整個集合,ArrayList和LinkedList執行效率基本一致。
第二:刪除元素及後續操作,這個如果刪除是最後一個元素,執行效率基本一致;如果是刪除的中間元素,那麼ArrayList需進行陣列元素移動,而LinkedList只需搭建起該元素的上一個節點和下一個節點的關係即可,LinkedList執行效率高於ArrayList。
因此,需根據實際情況才可判斷實際的執行效率。
問:遍歷效率這個問題怎麼說?
答:ArrayList通過陣列實現,天然可以通過陣列下標讀取資料,順序遍歷、隨機遍歷效率都非常高;LinkedList通過雙向連結串列實現,順序遍歷時,可直接通過本節點.next()直接找到相關聯的下一個節點,效率很高,而如果LinkedList隨機遍歷時,首先需判斷(傳遞的索引值與集合長度/2)的大小,來確定接下來是應該從第一個節點開始找還是最後節點開始找,越是靠近集合中部、集合越大,隨機遍歷執行效率越低。
四. 總結
本文對List集合進行了總結,包括類結構圖,ArrayList和Vector對比分析,ArrayList和LinkedList的對比分析,若有不對之處,請批評指正,望共同進步,謝謝!