源碼解析(JDK1.8)之——LinkedList

1 LinkedList

1.1 底層結(jié)構(gòu)
底層的數(shù)據(jù)結(jié)構(gòu)是雙向鏈表結(jié)構(gòu),有一個頭結(jié)點和一個尾結(jié)點,雙向鏈表意味著我們可以從頭開始正向遍歷,或者是從尾開始逆向遍歷,并且可以針對頭部和尾部進行相應(yīng)的操作。

LinkedList的數(shù)據(jù)結(jié)構(gòu)

1.2 優(yōu)缺點
雙向鏈表實現(xiàn),增刪快,查找慢

2 四個關(guān)注點

關(guān)注點 結(jié)論
LinkedList是否允許空 允許
LinkedList是否允許重復(fù)數(shù)據(jù) 允許
LinkedList是否有序 有序
LinkedList是否線程安全 非線程安全

3 LinkedList源碼解析

3.1 類的繼承關(guān)系

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

說明:LinkedList的類繼承結(jié)構(gòu)很有意思,我們著重要看是Deque接口,Deque接口表示是一個雙端隊列,那么也意味著LinkedList是雙端隊列的一種實現(xiàn),所以,基于雙端隊列的操作在LinkedList中全部有效。

3.2 類的內(nèi)部類

 private static class Node<E> {
        E item; // 數(shù)據(jù)域
        Node<E> next; // 后繼
        Node<E> prev; // 前驅(qū)
        
        // 構(gòu)造函數(shù),賦值前驅(qū)后繼
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
}

說明:內(nèi)部類Node就是實際的結(jié)點,用于存放實際元素的地方。

3.3 類的屬性

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    // 實際元素個數(shù)
    transient int size = 0;
    // 頭結(jié)點
    transient Node<E> first;
    // 尾結(jié)點
    transient Node<E> last;
}    

說明:LinkedList的屬性非常簡單,一個頭結(jié)點、一個尾結(jié)點、一個表示鏈表中實際元素個數(shù)的變量。注意,頭結(jié)點、尾結(jié)點都有transient關(guān)鍵字修飾,這也意味著在序列化時該域是不會序列化的。

3.4 類的構(gòu)造函數(shù)

1. LinkedList()型構(gòu)造函數(shù)

public LinkedList() {
}

2. LinkedList(Collection<? extends E>)型構(gòu)造函數(shù)

 public LinkedList(Collection<? extends E> c) {
        // 調(diào)用無參構(gòu)造函數(shù)
        this();
        // 添加集合中所有的元素
        addAll(c);
}

說明:會調(diào)用無參構(gòu)造函數(shù),并且會把集合中所有的元素添加到LinkedList中。

3.5 核心函數(shù)分析

1.add函數(shù)

public boolean add(E e) {
        // 添加到末尾
        linkLast(e);
        return true;
}

說明:add函數(shù)用于向LinkedList中添加一個元素,并且添加到鏈表尾部。具體添加到尾部的邏輯是由linkLast函數(shù)完成的。

void linkLast(E e) {
        // 保存尾結(jié)點,l為final類型,不可更改
        final Node<E> l = last;
        // 新生成結(jié)點的前驅(qū)為l,后繼為null
        final Node<E> newNode = new Node<>(l, e, null);
        // 重新賦值尾結(jié)點
        last = newNode;    
        if (l == null) // 尾結(jié)點為空
            first = newNode; // 賦值頭結(jié)點
        else // 尾結(jié)點不為空
            l.next = newNode; // 尾結(jié)點的后繼為新生成的結(jié)點
        // 大小加1    
        size++;
        // 結(jié)構(gòu)性修改加1
        modCount++;
}

說明:對于添加一個元素至鏈表中會調(diào)用add方法 -> linkLast方法。

示例(向LinkedList中添加兩個元素)

List<Integer> lists = new LinkedList<Integer>();
lists.add(5);
lists.add(6);
函數(shù)調(diào)用過程

2.addAll函數(shù)
addAll有兩個重載函數(shù),addAll(Collection<? extends E>)型和addAll(int, Collection<? extends E>)型,我們平時習(xí)慣調(diào)用的addAll(Collection<? extends E>)型可轉(zhuǎn)化為addAll(int, Collection<? extends E>)型,所以我們著重分析此函數(shù)即可。

// 添加一個集合
public boolean addAll(int index, Collection<? extends E> c) {
        // 檢查插入的的位置是否合法
        checkPositionIndex(index);
        // 將集合轉(zhuǎn)化為數(shù)組
        Object[] a = c.toArray();
        // 保存集合大小
        int numNew = a.length;
        if (numNew == 0) // 集合為空,直接返回
            return false;

        Node<E> pred, succ; // 前驅(qū),后繼
        if (index == size) { // 如果插入位置為鏈表末尾,則后繼為null,前驅(qū)為尾結(jié)點
            succ = null;
            pred = last;
        } else { // 插入位置為其他某個位置
            succ = node(index); // 尋找到該結(jié)點
            pred = succ.prev; // 保存該結(jié)點的前驅(qū)
        }

        for (Object o : a) { // 遍歷數(shù)組
            @SuppressWarnings("unchecked") E e = (E) o; // 向下轉(zhuǎn)型
            // 生成新結(jié)點
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null) // 表示在第一個元素之前插入(索引為0的結(jié)點)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) { // 表示在最后一個元素之后插入
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }
        // 修改實際元素個數(shù)
        size += numNew;
        // 結(jié)構(gòu)性修改加1
        modCount++;
        return true;
}

說明:參數(shù)中的index表示在索引下標(biāo)為index的結(jié)點(實際上是第index + 1個結(jié)點)的前面插入。在addAll函數(shù)中,addAll函數(shù)中還會調(diào)用到node函數(shù),get函數(shù)也會調(diào)用到node函數(shù),此函數(shù)是根據(jù)索引下標(biāo)找到該結(jié)點并返回,具體代碼如下

Node<E> node(int index) {
        // 判斷插入的位置在鏈表前半段或者是后半段
        if (index < (size >> 1)) { // 插入位置在前半段
            Node<E> x = first; 
            for (int i = 0; i < index; i++) // 從頭結(jié)點開始正向遍歷
                x = x.next;
            return x; // 返回該結(jié)點
        } else { // 插入位置在后半段
            Node<E> x = last; 
            for (int i = size - 1; i > index; i--) // 從尾結(jié)點開始反向遍歷
                x = x.prev;
            return x; // 返回該結(jié)點
        }
}

說明:在根據(jù)索引查找結(jié)點時,會有一個小優(yōu)化,結(jié)點在前半段則從頭開始遍歷,在后半段則從尾開始遍歷,這樣就保證了只需要遍歷最多一半結(jié)點就可以找到指定索引的結(jié)點。

示例

函數(shù)調(diào)用過程

3. remove函數(shù)

public boolean remove(Object o) {
        if (o == null) {  //刪除的元素為空
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {  //刪除的元素不為空
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
}

說明:在調(diào)用remove移除結(jié)點時,會調(diào)用到unlink函數(shù),unlink函數(shù)具體如下:

E unlink(Node<E> x) {
        // 保存結(jié)點的元素
        final E element = x.item;
        // 保存x的后繼
        final Node<E> next = x.next;
        // 保存x的前驅(qū)
        final Node<E> prev = x.prev;
        
        if (prev == null) { // 前驅(qū)為空,表示刪除的結(jié)點為頭結(jié)點
            first = next; // 重新賦值頭結(jié)點
        } else { // 刪除的結(jié)點不為頭結(jié)點
            prev.next = next; // 賦值前驅(qū)結(jié)點的后繼
            x.prev = null; // 結(jié)點的前驅(qū)為空,切斷結(jié)點的前驅(qū)指針
        }

        if (next == null) { // 后繼為空,表示刪除的結(jié)點為尾結(jié)點
            last = prev; // 重新賦值尾結(jié)點
        } else { // 刪除的結(jié)點不為尾結(jié)點
            next.prev = prev; // 賦值后繼結(jié)點的前驅(qū)
            x.next = null; // 結(jié)點的后繼為空,切斷結(jié)點的后繼指針
        }

        x.item = null; // 結(jié)點元素賦值為空
        // 減少元素實際個數(shù)
        size--; 
        // 結(jié)構(gòu)性修改加1
        modCount++;
        // 返回結(jié)點的舊元素
        return element;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容