LinkedHashMap原始碼解析

2021-09-20 15:17:22 字數 4570 閱讀 2768

2、方法字段

3、關鍵方法

4、總結

1.1 解釋說明

/**

* 雜湊表和煉表實現了map介面,具有可**的迭代順序(也就是說linkedhashmap是有序的)

* 這個工具不同於hashmap因為它在entry節點上多維護了一組雙向鍊錶,用來保證entry

* 插入有序。(我們知道在hashmap中每乙個桶中的節點用乙個單鏈表或者紅黑樹維護)

* 這個雙向鍊錶保證了entry的迭代順序(也就是保證entry有序),通常是鍵插入的順序。

* 但是要注意,如果乙個鍵是重新插入並不會影響它的順序(也就是說如果鍵存在,那麼

* 再插入乙個相同的key的時候,它首先會執行m.containskey(),如果存在則返回true)

* ** 這個實現使它的客戶端避免了由hashmap和hashtable所提供的未指定的、通常是混亂

* 的排序,並且不會增加類似於treemap的成本(這裡不是很理解treemap**成本比較高

* 等以後看了treemap再回來看看)。它還可以生成與原始map相同的副本,而不管原始map

* 的實現方式。

** void foo(map m)

*

*

* * 如果乙個模組接收輸入,複製它,然後又副本決定其返回的順序。那麼這個工具會非常有用。

* 客戶端通常喜歡按照他們提交的順序顯示結果。

* *

* linkedhashmap(int,float,boolean) 這個建構函式一共乙個建立鏈式hashmap,它的迭代順序

* 是它的entry最後一次被訪問。從最近最少訪問到最近最多訪問。這種方式的對映特別適用於

* lru快取(最近最少使用),呼叫、、、、

* 、、或

* 方法會導致對相應entry的訪問(假設在呼叫完成後存在)。如果值被替換,方法

* 只會導致對entry的訪問。方法為指定對映中的每個對映生成乙個entry訪問,其順序

* 是鍵值對映由指定對映的entry集迭代器提供。沒有其他方法生成entry訪問。,尤其是對集合

* 檢視的操作而不是會影響支援對映的迭代順序。

* *

* 可以通過重寫removeeldestentry(map.entry)方法,以便在向對映新增對映時強制執行自動刪除

* 陳舊的對映。(一般用鍊錶的形式進行儲存資料都需要有乙個刪除的過程,不然記憶體空間會爆滿的)

* *

* 這個類提供了map的所有操作(因為它繼承了hashmap且實現了map介面),且允許空值。跟hashmap一樣,

* 它提供固定的時間複雜度的效能對於基本的操作,像add(),contains()還有remove()。假設元素被均勻

* 的分配到每個桶中,則linkedhashmap的效能可能會比hashmap的效能稍微低一點,因為要維護鍊錶的開銷。

* 但是有乙個例外,linkedhashmap迭代集合元素的時候,只跟集合中的元素個數有關,而於桶的多少無關。

* 但是hashmap是跟桶的容量大小成正比的,因為它要從第乙個桶乙個個找過去。

* *

* linkedhashmap也有兩個屬性影響它的效能,初始容量和裝載因子。這個於hashmap一樣。但是要注意的是,

* 如果把初始容量定的太高的話,對於linedhashmap的影響比hashmap低,原因我們在前面已經說過了,那是

* 因為linkedhashmap的迭代不受初始容量的影響。

* *

* 這個方法也是非執行緒安全的。如果有多個執行緒訪問,且至少有乙個執行緒修改了map,則必須外部自己加鎖。

* 這通常是通過在一些自然封裝對映的物件上進行同步來實現的。

* *

* 如果不存在這樣的物件,則應該使用方法。這最好在建立時完成,以防止意外地不同步地訪問對映:

* map m = collections.synchronizedmap(new linkedhashmap(...));

* *

* 乙個結構性修改是指新增或者刪除乙個或者多個對映的操作,又或者是在訪問hash鍊錶的情況下

* 影響了迭代的順序。在插入順序鏈結雜湊對映中,僅更改與對映中已包含的鍵關聯的值不是結構

* 性修改。在訪問順序的鏈結雜湊對映中,僅用get()查詢對映是一種結構修改。

* *

* 跟hashmap一樣,迭代器也是採用"fail-fast"來對併發的結構性修改丟擲異常,但是也不能用這個

* 來保證併發性的修改,它只是檢測bug,最終還是要靠外部的同步來保證併發的修改安全。

1.2 資料結構

跟hashmap相比較主要多了乙個雙向鍊錶來維護entry,圖中的黑色雙向線。在jdk1.8中也是採用(陣列+單鏈表+雙向鍊錶+紅黑樹)

/**

* 在繼承了hashmap的節點的基礎上,新增了雙向鍊錶

*/static

class

entry

extends

hashmap.node

}//序列號

private

static

final

long serialversionuid =

3801124242820219131l;

/** * 雙向鍊錶的頭結點

*/transient linkedhashmap.entry

head;

/** * 雙向鍊錶的尾結點

*/transient linkedhashmap.entry

tail;

/** *迭代的排序方法,如果是true,則按順序,

*為false,則不按順序

* @serial

*/final

boolean accessorder;

從欄位可以發現主要是繼承自hashmap然後增加了乙個雙向鍊錶和乙個指向頭尾的指標,主要用來插入和刪除的方便。還有乙個accessorder主要用來指定要不要按照順序插入。

linknodelast(linkedhashmap.entryp)

// 將節點鏈結到鍊錶末尾

private

void

linknodelast

(linkedhashmap.entry

p)}

transferlinks(linkedhashmap.entrysrc, linkedhashmap.entrydst)

// 其中的dst:destination目的節點,src:source源節點,這個函式的作用

//就是用dst節點替換掉src節點,整個過程就是乙個雙向鍊錶的替換節點過程

private

void

transferlinks

(linkedhashmap.entry

src,

linkedhashmap.entry

dst)

這個方法是用來替換節點的,當對映到相同的key,想要替換掉對應的value就呼叫這個方法,可以看到這個是乙個private方法,說明它是在內部呼叫,提供給我們的是其他方法比如replacementnode方法,主要的實現如圖所示。

//刪除節點

void

afternoderemoval

(node

e)

afternodeinsertion(boolean evict)

//插入節點,如果存在相同key,可能刪除第乙個舊的節點

void

afternodeinsertion

(boolean evict)

}

afternodeaccess(nodee)

//訪問節點,則會將訪問的節點會被移到鍊錶的最後位置,這個方法和afternoderemoval(),就可以實現lru演算法

void

afternodeaccess

(node

e) tail = p;

++modcount;

}}

總的來說linkedhashmap主要是繼承自hashmap,hashmap有的linkedhashmap也都可以實現。最主要的區別在於linkedhashmap多了雙向鍊錶來維護節點的順序,使節點按插入的時間有序,此外還有乙個就是實現了插入新節點的時候能夠判斷是否要刪除舊節點,可以用這個來實現lru演算法。

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...