List原始碼分析

kk阿彬發表於2020-11-23

ArrayList

在這裡插入圖片描述

public class ArrayList<E> extends AbstractList<E>
 implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{}

在這裡插入圖片描述
根據上面我們可以清晰的發現:ArrayList底層其實就是一個陣列,ArrayList中有擴容這麼一個概念,正因為它擴容,所以它能夠實現“動態”增長

以上是怎麼得到的結論?由建構函式得出的
在這裡插入圖片描述

add(E e)

步驟:

檢查是否需要擴容
插入元素
首先,我們來看看這個方法:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

該方法很短,我們可以根據方法名就猜到他是幹了什麼:

確認list容量,嘗試容量加1,看看有無必要
新增元素
接下來我們來看看這個小容量(+1)是否滿足我們的需求:
在這裡插入圖片描述
隨後呼叫ensureExplicitCapacity()來確定明確的容量,我們也來看看這個方法是怎麼實現的:
在這裡插入圖片描述
grow擴容:
在這裡插入圖片描述
copyOf方法
在這裡插入圖片描述
到目前為止,我們就可以知道add(E e)的基本實現了:

首先去檢查一下陣列的容量是否足夠

足夠:直接新增

不足夠:擴容

擴容到原來的1.5倍
第一次擴容後,如果容量還是小於minCapacity,就將容量擴充為minCapacity。

add(int index, E element)

步驟:

檢查角標
空間檢查,如果有需要進行擴容
插入元素
我們來看看插入的實現:
在這裡插入圖片描述

我們發現,與擴容相關ArrayList的add方法底層其實都是arraycopy()來實現的

看到arraycopy(),我們可以發現:該方法是由C/C++來編寫的,並不是由Java實現:

在這裡插入圖片描述

總的來說:arraycopy()還是比較可靠高效的一個方法。

get/remove等方法以後再說
總結:
ArrayList是基於動態陣列實現的,在增刪時候,需要陣列的拷貝複製。
ArrayList的預設初始化容量是10,每次擴容時候增加原先容量的一半,也就是變為原來的1.5倍
刪除元素時不會減少容量,若希望減少容量則呼叫trimToSize()
它不是執行緒安全的。它能存放null值。

在這裡插入圖片描述

Arraylist 和 Vector 的區別?

ArrayList 是 List 的主要實現類,底層使用 Object[ ]儲存,適用於頻繁的查詢工作,執行緒不安全 ;
Vector 是 List 的古老實現類,底層使用 Object[ ]儲存,執行緒安全的。
ArrayList在底層陣列不夠用時在原來的基礎上擴充套件0.5倍,Vector是擴充套件1倍。
Vector執行緒安全是因為方法上加了synchronized.
在這裡插入圖片描述

LinkedList

在這裡插入圖片描述

public class LinkedList<E>
 extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{}

建構函式
在這裡插入圖片描述

add

add方法
如果做過連結串列的練習,對於下面的程式碼並不陌生的~

add方法實際上就是往連結串列最後新增元素

    public boolean add(E e) {
        linkLast(e);
        return true;
    }void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

List集合總結

ArrayList、LinkedList、Vector算是在面試題中比較常見的的知識點了。下面我就來做一個簡單的總結:

ArrayList:

底層實現是陣列
ArrayList的預設初始化容量是10,每次擴容時候增加原先容量的一半,也就是變為原來的1.5倍
在增刪時候,需要陣列的拷貝複製(navite 方法由C/C++實現)
LinkedList:

底層實現是雙向連結串列[雙向連結串列方便實現往前遍歷]
Vector:

底層是陣列,現在已少用,被ArrayList替代,原因有兩個:

Vector所有方法都是同步,有效能損失
Vector初始length是10 超過length時 以100%比率增長,而ArrayList是50%。相比於ArrayList更多消耗記憶體。
總的來說:查詢多用ArrayList,增刪多用LinkedList。

ArrayList增刪快的幾種極端情況:

在末尾增刪+中間刪除都是ArrayList快

相關文章