Java 集合之LinkedList

麥克斯維發表於2019-03-02

1.回顧

在上一篇介紹了Java 集合之ArrayList主要講解了ArrayList的一些方法和具體實現,ArrayList是基於陣列來實現,當插入新元素時,其後面的元素的位置都需要移動,這顯而易見是個影響效能的操作,資料量一大,再頻繁的執行插入操作那…照例我們先看集合的結構圖

Java 集合之LinkedList

2.結構

LinkedList和ArrayList 同屬於List介面的,看下詳細的結構圖實現類,那麼兩者的方法應該大致相同

Java 集合之LinkedList

AbstractSequentialList類是 AbstractList的一個子類,提供了一個基本的list介面實現,為了順序訪問的資料儲存結構(連結串列)提供了最小化的實現。AbstractSequentiaList是在迭代器基礎上實現的get、set、add等方法。

Deque介面繼承Queue介面,兩端都允許插入和刪除元素,即雙向佇列。

實現了Cloneable,能被克隆,實現了Serializable,支援序列化

我們檢視下LinkedList類中的方法

Java 集合之LinkedList

順便附上AbstractSequentiaList抽象類方法

Java 集合之LinkedList

通過檢視原始碼發現AbstractSequentiaList是在迭代器基礎上實現的get、set、add等方法,而這個迭代是在子類去實現

 public abstract ListIterator<E> listIterator(int index);
複製程式碼

3.原始碼分析

一.成員變數

transient int size = 0;
transient Node<E> first;
transient Node<E> last;
複製程式碼
  • size 元素個數
  • first 指向頭節點
  • last 指向尾節點

Node是個內部類

 private static class Node<E> {
        E item; //結點的值
        Node<E> next;   //結點的後向指標
        Node<E> prev;   //結點的前向指標

        //構造方法中已完成Node成員的賦值
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;    //結點的值賦值為element
            this.next = next;       //後向指標賦值
            this.prev = prev;       //前向指標賦值
        }
    }

複製程式碼

二.構造方法

public LinkedList() {
    }

public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}
複製程式碼

空構造方法構造了一個空的List 其中size為0 first和last都為null ,沒有任何元素
LinkedList(Collection<? extends E> c)構造一個包含指定Collection中所有元素的列表 該方法先呼叫空構造器 然後addAll()把Collection中所有元素新增進去

三.常用方法

addAll

public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }
 public boolean addAll(int index, Collection<? extends E> c) {
    checkPositionIndex(index);//檢查是否越界

    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;

    Node<E> pred, succ;
    if (index == size) {
        succ = null;
        pred = last;
    } else {
        succ = node(index);
        pred = succ.prev;
    }

    for (Object o : a) {////for迴圈結束後,a裡面的元素都新增到當前連結串列裡面,後向新增
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }

    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }

    size += numNew;
    modCount++;
    return true;
}
複製程式碼

此方法較長 主要操作就是檢查index是否越界 將collection轉化成陣列 迴圈陣列將陣列裡面的元素建立為節點 並按照順序連起來
修改當前節點個數size

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++;
    }    
複製程式碼

add 方法直接呼叫了 linkLast 方法,而 linkLast 方法是不對外開放的。該方法做了三件事情,新增一個節點,改變其前後引用,將 size 和 modCount 自增 1。其中 modCount 是記錄對集合操作的次數。

remove

 public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
 E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }    
複製程式碼

檢查下標是否越界,然後呼叫 unlink 釋放節點。
還有其他方法這裡就不一一列舉了

四 總結

結合原始碼我們大致可以知道LinkedList裡維持了一個連結串列 每個連結串列單元是一個Node Node的prev指向前一個節點 next指向後一個節點 這樣所有節點都串了起來 如圖

Java 集合之LinkedList

有幾點需要注意的是

  • LinkedList的實現是基於雙向連結串列的,且頭結點中不存放資料
  • LinkedList是基於連結串列實現的,因此不存在容量不足的問題,所以這裡沒有擴容的方法 不同與陣列實現的ArrayList
  • LinkedList是基於連結串列實現的,插入刪除效率高,查詢效率低

若經常查詢又很少插入和刪除 則推薦使用ArrayList
相反經常插入與刪除 很少查詢 則推薦使用LinkedList
日常開發中,當然是ArrayList的使用頻率更高些。下一篇準備講解下Set系列…

Java 集合之LinkedList

相關文章