1. 程式人生 > 其它 >JAVA LinkedList原始碼分析

JAVA LinkedList原始碼分析

LinkedList底層結構

一、LinkedList 的全面說明

  1. LinkedList底層實現了雙向連結串列和雙端佇列的貼點
  2. 可以新增任意元素(元素可以重複),包括null
  3. 執行緒不安全,沒有實現同步
    • 不涉及到多執行緒時使用

二、 LinkedList 的底層操作機制

package com.hspedu.list_;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * @author DL5O
 * @version 1.0
 */
@SuppressWarnings("all")
public class LinkedListCRUD {

    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);

        System.out.println("linkedList = " + linkedList);//[1, 2, 3]
        linkedList.remove();//刪除第一個節點
//        linkedList.remove(1);//刪除第二個節點
//        linkedList.remove(new Integer(1));//指定刪除
        System.out.println(linkedList);//[2, 3]

        //修改某個節點物件
        linkedList.set(1,999);
        System.out.println(linkedList);//[2, 999]

        //得到某個節點物件
        Object o = linkedList.get(1);
        System.out.println(o);

        //因為linkedList實現了 list介面,所以它的遍歷方式可以是增強for或者是迭代器
        Iterator iterator = linkedList.iterator();
        while(iterator.hasNext()){
            Object next = iterator.next();
            System.out.print(next+" ");
        }
        //2 999
        System.out.println();
        //原始碼閱讀
        /*
            1.new 一個LinkedList後,呼叫它的無參構造器
                public LinkedList() {}
            2.這時linkedlist 的屬性 first = null, last = null;
            3.執行
                public boolean add(E e) {
                    linkLast(e);
                    return true;
                }
            4.這時把插入的元素,插入到連結串列的尾部
                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++;
                }
         */


        /*
            刪除remove的原始碼
            1.
            public E remove() {
                return removeFirst();
            }
            2.執行
            public E removeFirst() {
                final Node<E> f = first;
                if (f == null)
                    throw new NoSuchElementException();
                return unlinkFirst(f);
            }

            3.執行 unlinkLast,將 f 指向的雙向連結串列的第一個結點拿掉(刪除)
            private E unlinkLast(Node<E> l) {
                // assert l == last && l != null;
                final E element = l.item;
                final Node<E> prev = l.prev;
                l.item = null;
                l.prev = null; // help GC
                last = prev;
                if (prev == null)
                    first = null;
                else
                    prev.next = null;
                size--;
                modCount++;
                return element;
            }
         */

    }
}

原始碼分析

1.新增

第一次新增

  • 首先讓節點 l 指向尾節點 last

    • last 預設為null
  • 建立一個名為newNode的新節點,new Node<>(前驅,元素值,後繼)

    • 因為這裡是第一次新增元素到這個雙向連結串列(linkLast集合)中,l指向的last為空,新建立的節點,前驅為null
  • last指標指向新節點,即新節點就變成了尾節點

  • 如果 l==null,代表該連結串列現在沒有元素,就讓頭節點也指向這個新節點,這時該連結串列中的第一個元素就誕生了

  • size ++,表長加加

第二次新增

2.刪除

  • 刪除連結串列的頭節點,即首個節點
    • 如果 f == null,即該連結串列沒有結點,為空連結串列,就丟擲異常
  • 呼叫unlinkFirst方法將頭節點的地址作為引數傳進去,進行刪除操作
  • 用一個只讀泛型 element 來接受 頭結點的 資料

  • next 為 頭結點的下一個節點

  • 讓 f(頭結點)的資料域和next域置空(讓GC回收)

  • 讓後讓頭指標 指向 next(被刪除的節點的下一個節點)

  • 如果next == null,連結串列為空,讓last也指向null

    • 如果不為空,就讓新的頭結點(next)的prev設為null

三、ArrayList和LinkedList比較

底層結構 增刪效率 改查效率
ArrayList 可變陣列 較低,陣列擴容 較高
LinkedList 雙向連結串列 較高,通過連結串列追加 較低
  1. 如果我們改查的操作多,就選擇ArrayList
  2. 如果我們增刪的操作多,就選擇LinkedList
  3. 一般來說,在程式中,80%~90%都是查詢因此大部分情況下都會選擇ArrayList
  4. 在一個專案中,根據業務靈活選擇,也可能這樣,一個模組使用ArrayList一個模組使用LinkedList,也就是說根據業務來進行合理選擇

注意:

  • 這兩個集合都是執行緒不安全的,建議在不涉及到多執行緒時使用