JAVA LinkedList原始碼分析
阿新 • • 發佈:2022-03-09
LinkedList底層結構
一、LinkedList 的全面說明
- LinkedList底層實現了雙向連結串列和雙端佇列的貼點
- 可以新增任意元素(元素可以重複),包括null
-
執行緒不安全,沒有實現同步
- 不涉及到多執行緒時使用
二、 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
- 因為這裡是第一次新增元素到這個雙向連結串列(linkLast集合)中,l指向的
-
讓
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 | 雙向連結串列 | 較高,通過連結串列追加 | 較低 |
- 如果我們改查的操作多,就選擇ArrayList
- 如果我們增刪的操作多,就選擇LinkedList
- 一般來說,在程式中,80%~90%都是查詢,因此大部分情況下都會選擇ArrayList
- 在一個專案中,根據業務靈活選擇,也可能這樣,一個模組使用ArrayList一個模組使用LinkedList,也就是說根據業務來進行合理選擇
注意:
- 這兩個集合都是執行緒不安全的,建議在不涉及到多執行緒時使用