1. 程式人生 > >jdk原始碼閱讀二:LinkedList

jdk原始碼閱讀二:LinkedList

LinkedList介紹

這裡寫圖片描述

LinkedList是基於連結串列來實現的List。主要特徵如下:

  • 不僅實現了List介面,還實現了Deque,所以是一個雙端佇列。
  • 允許儲存null物件。
  • 非執行緒安全,如果多執行緒操作它,需要外部枷鎖,或者Collections.synchronizedList。
  • 返回的iterator是fail-fast,如果iterator建立後,修改了list結構則會丟擲異常ConcurrentModificationException, 注意這裡異常表明是一個bug,需要避免,而不能處理業務邏輯。

size 變數

size 表示當前list中儲存了元素的個數,初始化為0。add一個元素加一,刪除一個元素減一。
它和ArrayList定義不一樣,加了transient

關鍵字,表明序列化時候忽略該欄位。

 transient int size = 0;

容量增長策略

因為是基於連結串列儲存元素,所以容量受限於堆記憶體。沒有擴容一說。所以不存在ensureCapacity*的方法。
接下來我們主要看看LinkedList的List和Deque功能實現。

底層儲存策略

關於儲存的成員變數主要如下:

transient Node<E> first;
transient Node<E> last;

儲存著連結串列的第一個和最後一個元素。

它有兩個建構函式:

public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

呼叫預設的建構函式:first,last都是null,size =0。
呼叫第二個建構函式,添加了一個集合到list。

Node類

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

Node類程式碼很簡單:

  • item儲存具體物件。
  • next表示該節點對應的下一個節點。
  • prev表示該節點對應的上一個節點。

常用curd操作

插入元素

有六個add*相關方法,

add(E e)

內部呼叫了linkLast(e)。

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    //判斷list是否第一次插入元素 
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

每次末尾插入一個新元素,並別該元素的prev元素也新增進去。這裡要說明第一次插入元素之前 list的fist和last都為null。

add(E e)

public void add(int index, E element) {
    //檢查index是否合法,index在[0,size]之內,否則丟擲異常
    checkPositionIndex(index);
    //在末尾插入元素
    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

linkBefore方法傳一個node(index)方法。該方法就是找到index位置的Node節點。如果 index

addFirst

因為是雙端佇列,除了前面提到的隊尾插入還有隊頭插入元素方法,內部呼叫的linkFirst方法,其實與linkLast類似。

unlink*方法分析

除了前面介紹的link*方法,還有三個unlink* 方法,作用是幹嘛呢?link*是插入元素到列表,unlink其實是從連結串列刪除一個節點意思。

  1. unlinkFirst:刪除隊頭的節點。
  2. unlinkLast:刪除隊尾的節點。
  3. unlink :刪除中間的節點

佇列刪除

佇列有好幾個remove方法 內部都是呼叫了unlink方法。

get

getFirst 和getLast都很快。
get(index) 內部呼叫的node(index)方法定位的,前面已經提到過。

indexof,contains方法分析

contains呼叫了indexOf,
indexof是從頭開始查詢,lastIndexOf從尾部開始查詢,我們看下indexOf方法:

public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
    }
    return -1;
}

方法也是迴圈比較節點的內容和當前是否相等。

Deque 方法分析

Deque一般我們用的比較少。

Deque是一個線性集合,允許你在頭部和尾部插入和取出資料。

LinkedList實現了Deque介面,並且他是一個非阻塞的Deque。

下面我們分析下Deque的方法實現。

這裡寫圖片描述

add幾個方法已經見過,get也見過,我們主要分析Deque幾個不怎麼熟悉的方法。

offer*

offer也是增加元素的意思,類似於add

offer和offerLast表示在尾部加入元素。,內部也是呼叫了add*方法。
offerFirst表示頭部加入。下面是offerFirst程式碼:

 public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}

peek*

peek是檢視的意思,這裡也是檢視隊尾或者頭的元素。

peek和peekFirst 程式碼完全一樣。
peekLast檢視隊尾元素。

poll*

poll類似於peek,但是他會把對應額節點刪除。

pop*

pop*和poll*差不多,只是pop空節點 會丟擲異常。

push

加入元素 直接呼叫了addFirst。

removeFirstOccurrence等

removeFirstOccurrence內部直接呼叫了remove。

remove從頭迴圈刪除對應的一個元素。

removeLast當然是從隊尾迴圈刪除對應的一個元素。

相關推薦

jdk原始碼閱讀LinkedList

LinkedList介紹 LinkedList是基於連結串列來實現的List。主要特徵如下: 不僅實現了List介面,還實現了Deque,所以是一個雙端佇列。 允許儲存null物件。 非執行緒安全,如果多執行緒操作它,需要外部枷鎖,或者Collecti

JDK原始碼閱讀-------自學筆記(十三)(java.util.LinkedList 初探 自定義講解)

1、LinkedList簡介 (1) 底層用雙向連結串列實現的儲存 (2) 查詢效率低,頻繁增刪效率高,執行緒不安全是其主要特點 (3) 常用單詞Node/Entry表示一個節點,或稱為條項,詞條(形容節點的樣子) (4) 連結串列由三部分組成:前一個節點,本節點儲存的資料,後一個節點 2、LinkedL

JDK原始碼閱讀-------自學筆記(十四)(java.util.LinkedList 再探 自定義講解)

# 一、實現get方法 ## 1、一般思維實現思路 * 1)、將物件的值放入一箇中間變數中。 * 2)、遍歷索引值,將中間量的下一個元素賦值給中間量。 * 3)、返回中間量中的元素值。 * 4)、示意圖 ![](https://img2020.cnblogs.com/blog/994129/20201

JDK原始碼閱讀InterruptibleChannel與可中斷IO,ig牛逼

Java傳統IO是不支援中斷的,所以如果程式碼在read/write等操作阻塞的話,是無法被中斷的。這就無法和Thead的interrupt模型配合使用了。JavaNIO眾多的升級點中就包含了IO操作對中斷的支援。InterruptiableChannel表示支援中斷的Channel。我們常用的FileCha

jdk原始碼閱讀——linkedlist

首先還是從建構函式開始 /** * Constructs an empty list. */ public LinkedList() { } 是一個空的 然後我們從add看 public boolean add(E e) {

JDK原始碼閱讀ByteBuffer

Buffer是Java NIO中對於緩衝區的封裝。在Java BIO中,所有的讀寫API,都是直接使用byte陣列作為緩衝區的,簡單直接。但是在Java NIO中,緩衝區這一概念變得複雜,可能是對應Java堆中的一塊記憶體,也可能是對應本地記憶體中的一塊記憶體。

jdk原始碼閱讀筆記-LinkedList

  一、LinkedList概述   LinkedList的底層資料結構為雙向連結串列結構,與ArrayList相同的是LinkedList也可以儲存相同或null的元素。相對於ArrayList來說,LinkedList的插入與刪除的速度更快,時間複雜度為O(1),查詢的速度就相對比較慢了,因為每次遍歷的時

圖解Java常用資料結構(一)\JDK原始碼分析()——LinkedList

最近在整理資料結構方面的知識, 系統化看了下Java中常用資料結構, 突發奇想用動畫來繪製資料流轉過程. 主要基於jdk8, 可能會有些特性與jdk7之前不相同, 例如LinkedList LinkedHashMap中的雙向列表不再是迴環的. HashMap中的單鏈表

JDK原始碼閱讀——LinkedList實現

1 繼承結構圖   LinkedList是List的另一種實現。繼承自AbstractSequentialList 2 資料結構 LinkedList與ArrayList不同的是LinkedList底層使用雙向連結串列進行儲存,其主要資料結構如下   // 記錄List長度   tr

jdk原始碼閱讀之HashMap(

HashMap的遍歷 HashMap對應有三種遍歷方式,分別是條目遍歷(可理解為節點遍歷)、鍵遍歷、值遍歷. //遍歷鍵的迭代器 final class KeyIterator extends HashIterator implements Iterator<K

jdk原始碼閱讀LinkedList

和ArrayList相似,LinkedList也是實現了List介面,但是LinkedList是用連結串列實現的,而ArrayList是用陣列實現的。兩者的優缺點基本就是連結串列和陣列的優缺點。 先看LinkedList宣告 public class LinkedList<E>

深挖JDK動態代理()JDK動態生成後的字節碼分析

sts write ext cloud hashcode 寫入 com erro closed 接上一篇文章深挖JDK動態代理(一)我們來分析一下JDK生成動態的代理類究竟是個什麽東西 1. 將生成的代理類編程一個class文件,通過以下方法 public

jdk原始碼閱讀之——arraylist

首先看一下他的建構函式: public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 其實arraylist還有其他的建構函式,可以指定陣列的長度,這裡先從最基本的入

SGISTL原始碼閱讀 空間配置器中(第二級配置器__default_alloc_template)

SGISTL原始碼閱讀二 空間配置器中(第二級配置器__default_alloc_template) 引入 SGI空間配置器的做法是,如果區塊夠大,超過了128bytes,就移交給第一級配置器處理。當區塊小於128bytes時就是第二級配置器要做的事情了。 SGI的第二級配置器維護

jdk原始碼閱讀筆記-LinkedHashMap

  Map是Java collection framework 中重要的組成部分,特別是HashMap是在我們在日常的開發的過程中使用的最多的一個集合。但是遺憾的是,存放在HashMap中元素都是無序的,原因是我們在put或get資料的時候都是根據key的hash值來確定元素的位置。在具體的業務場景中,我們更

jdk原始碼閱讀(ⅠSet介面相關類)

HashSet原始碼閱讀筆記 1、是建立在HashMap的基礎之上的,通過HashMap的各個方法進行實現的。 2、內部擁有一個HashMap,這個map就是儲存HashSet所有元素的。 3、內部還有一個假的Object物件。這個物件就是在向map中放入key的時候對應的value。無實際意義

jdk原始碼閱讀筆記-ArrayList

一、ArrayList概述 首先我們來說一下ArrayList是什麼?它解決了什麼問題?ArrayList其實是一個數組,但是有區別於一般的陣列,它是一個可以動態改變大小的動態陣列。ArrayList的關鍵特性也是這個動態的特性了,ArrayList的設計初衷就是為了解決Java陣列長度不可變的

JDK 原始碼閱讀 : DirectByteBuffer

在文章JDK原始碼閱讀-ByteBuffer中,我們學習了ByteBuffer的設計。但是他是一個抽象類,真正的實現分為兩類:HeapByteBuffer與DirectByteBuffer。HeapByteBuffer是堆內ByteBuffer,使用byte[]儲存資料,是

JDK 原始碼閱讀 Reference

Java最初只有普通的強引用,只有物件存在引用,則物件就不會被回收,即使記憶體不足,也是如此,JVM會爆出OOME,也不會去回收存在引用的物件。 如果只提供強引用,我們就很難寫出“這個物件不是很重要,如果記憶體不足GC回收掉也是可以的”這種語義的程式碼。Java

jdk原始碼閱讀之Object類

Object的作用 Object是java所有類的基類,定義了所有類的基礎方法 。這個類所定義的方法也不多,大部分是native方法。 什麼是native方法 native關鍵字標識的java方法為本地方法,底層是有c/c++編寫的程式編譯後dll檔案,jav