List集合總結,對比分析ArrayList,Vector,LinkedList

工匠初心發表於2019-06-30

前面已經寫了三篇關於Java集合的文章,包括:

Java集合 ArrayList原理及使用

再說Java集合,subList之於ArrayList

Java集合 LinkedList的原理及使用

關於Vector,它的實現和ArrayList非常類似,就不再單開一個章節來講了,現在我們來對Java集合做一個歸納總結。

一. List框架圖

List集合總結,對比分析ArrayList,Vector,LinkedList

首先上面的框架圖可以表明順序的關聯關係,但並不全面,如ArrayList在繼承了AbstractList抽象類的同時還實現了List介面。

  1. List是一個介面,繼承了Collection,同時Collection繼承了Iterable,表明List的實現類都是可用迭代遍歷的;
  2. AbstractList是一個抽象類,實現了List介面,同時繼承了AbstractCollection,針對一些常用方法,如add(),set(),remove(),給了預設實現,當然在具體的實現類中基本都重寫了,該類中沒有get(),size()方法。
  3. AbstractSequentialList是一個抽象類,繼承了AbstractList抽象類,實現了很多雙向連結串列中根據索引操作的方法。
  4. 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的對比分析,若有不對之處,請批評指正,望共同進步,謝謝!

相關文章