LinkedHashMap 原始碼解析

2021-10-06 10:22:03 字數 4475 閱讀 8266

linkedhashmap 繼承了 hashmap 類,是 hashmap 的子類,linkedhashmap 的大多數方法的實現直接使用了父類 hashmap 的方法。linkedhashmap 可以說是 hashmap 和 linkedlist 的結合體,既使用了 hashmap 的資料結構,又借用了 linkedlist 雙向鍊錶的結構。

linkedhashmap 實現與 hashmap 的不同之處在於,後者維護著乙個執行於所有條目的雙向鍊錶。此鍊錶定義了迭代順序,該迭代順序可以是插入順序或者是訪問順序。

注意,此實現不是同步的。如果多個執行緒同時訪問鏈結的雜湊對映,而其中至少乙個執行緒從結構上修改了該對映,則它必須保持外部同步。

linkedhashmap 繼承了 hashmap 類,有著和 hashmap 類似的操作。

public

class

linkedhashmap

extends

hashmap

implements

map

在 hashmap 的基礎上,linkedhashmap 新增了 head 和 tail 屬性,表示指向鍊錶的頭節點和尾節點。accessorder 表示按訪問順序遍歷還是按插入順序遍歷,如果 accessorder 為 true,表示按訪問順序遍歷,如果為 false,表示按插入順序遍歷。

linkedhashmap 有 5 種構造方法,大部分都在內部呼叫父類 hashmap 的構造方法。

public

linkedhashmap()

無參構造方法表示用預設的初始化容量和負載因子建立乙個 linkedhashmap,以插入順序取得鍵值對。

public

linkedhashmap

(int initialcapacity)

乙個引數的構造方法表示構造乙個指定初始容量的 linkedhashmap,以插入順序取得鍵值對。

public

linkedhashmap

(int initialcapacity,

float loadfactor)

兩個引數的構造方法表示構造乙個指定初始容量和負載因子的 linkedhashmap,以插入順序取得鍵值對。

public

linkedhashmap

(int initialcapacity,

float loadfactor,

boolean accessorder)

三個引數的構造方法表示根據指定容量、裝載因子和鍵值對保持順序建立乙個 linkedhashmap。

public

linkedhashmap

(map<

?extendsk,

?extends

v> m)

該構造方法通過傳入的 map 建立乙個 linkedhashmap,容量為預設容量和 map.size() / default_load_factory + 1 的較大者,裝載因子為預設值。

0x01、put(k key, v value)

linkedhashmap 的 put() 方法沿用了父類 hashmap 的 put() 方法,但我們也提到了像 linkedhashmap 的 entry 類就是繼承了 hashmap 的 node 類,同樣的,hashmap 的 put() 方法中呼叫的其他方法在 linkedhashmap 中已經被重寫。

newnode(int hash, k key, v value, nodee)

node

newnode

(int hash, k key, v value, node

e)private

void

linknodelast

(linkedhashmap.entry

p)}

linkedhashmap 重寫了 newnode() 方法,通過此方法保證了插入的順序性。

afternodeaccess(nodee)

void

afternodeaccess

(node

e)// 將節點 p 設定為尾節點

tail = p;

++modcount;

}}

關於 afternodeaccess() 方法,在 hashmap 中沒給具體實現,而在 linkedhashmap 重寫了,目的是保證操作過的 node 節點永遠在最後,從而保證讀取的順序性,在呼叫 put() 方法和 get() 方法時都會用到。

afternodeinsertion(boolean evict)

void

afternodeinsertion

(boolean evict)

}protected

boolean

removeeldestentry

(map.entry

eldest)

我們看到在 linkedhashmap 中還重寫了 afternodeinsertion(boolean evict) 方法,它的目的是移除鍊錶中最老的節點物件,也就是當前在頭部的節點物件,但實際上在 jdk 8 中不會執行,因為 removeeldestentry() 方法始終返回 false。

0x02、get(object key)

public v get

(object key)

linkedhashmap 的 get() 方法與 hashmap 中 get() 方法的不同點在於多了 afternodeaccess() 方法,afternodeaccess() 方法在上文已經講過。

0x03、remove(object key)

public v remove

(object key)

final node

removenode

(int hash, object key, object value,

boolean matchvalue,

boolean movable)

p = e;

}while

((e = e.next)

!= null);}

}if(node != null &&

(!matchvalue ||

(v = node.value)

== value ||

(value != null && value.

equals

(v))))

}return null;

}

remove() 方法也直接使用了 hashmap 中的 remove(),在 hashmap 章節中並沒有講解,因為 remove() 的原理很簡單,通過傳遞的引數 key 計算出 hash,據此可找到對應的 node 節點,如果該 node 節點是直接在陣列中的 node,則將 table 陣列該位置的元素設定為 node.next,如果是鍊錶中的,則遍歷鍊錶,直到找到對應的 node 節點,然後將該節點的上乙個節點的 next 設定為該節點的 next。

void

afternoderemoval

(node

e)

linkedhashmap 重寫了其中的 afternoderemoval(node e),該方法在 hashmap 中沒有具體實現,通過此方法在刪除節點的時候調整了雙鏈表的結構。

linkedhashmap 繼承於 hashmap,是基於 hashmap 和雙向鍊錶來實現的。

hashmap 無序,linkedhashmap 有序,可分為插入順序和訪問順序兩種。如果是訪問順序,那 put() 和 get() 操作已存在的 entry 時,都會把 entry 移動到雙向鍊錶的表尾(其實是先刪除再插入)。

linkedhashmap 訪問資料,還是跟 hashmap 一樣使用的 entry 的方式,雙向鍊錶只是為了保證順序。

linkedhashmap 是執行緒不安全的。

參考

AbstractCollection原始碼分析

abstractcollection抽象類提供了collection的骨架實現,collection分析請看 這裡直接看它的 是如何實現的.public abstract iterator iterator 該方法沒有實現.public abstract int size 該方法沒有實現.publi...

ThreadPoolExecutor原始碼閱讀

執行緒池解決兩個問題 一是復用執行緒,減少建立銷毀執行緒帶來系統開銷 二是限定系統資源使用邊界,避免大量執行緒消耗盡系統記憶體 適用於互不依賴,執行時間短,不需要對執行緒控制操作的執行緒 新增任務時,1.若執行緒數量小於corepoolsize,則新增執行緒執行任務 2.若執行緒數量大於等於core...

OrangePi One Android 原始碼編譯

一 系統環境搭建參照 二 lichee原始碼編譯 1.檢視help build.sh h2.配置核心 cd linux 3.4 make arch arm menuconfig 進入配置頁面,上下移動列表,空格是選擇列表,左右移動選擇退出選項 3.首次編譯執行清除 在 lichee linux3.4...