LinkedHashMap原始碼分析及實現LRU演算法

2021-09-01 03:00:17 字數 4146 閱讀 7773

ps: 要先了解hashmap的實現原理hashmap原始碼分析

可以看到linkedhashmap繼承了hashmap,其實際是在hashmap基礎上,把資料節點連成乙個雙向鍊錶,遍歷的時候按鍊錶順序遍歷。

小總結預設的linkedhashmap 的遍歷會按照插入的順序遍歷出來,hashmap則不保證順序。

注意上面是預設的情況,linkedhashmap中還有個accessorder成員標誌,預設是false,當為true時,每get乙個元素,都會把這個元素放在鍊錶最後,即遍歷的時候就變成最後被遍歷出來。

//通過繼承hashmap.node類,新增兩個成員,before, after實現鍊錶

static

class

entry

extends

hashmap.node

}

這裡繼承了父類hashmap的node類,新增了兩個成員before,after,用於實現鍊錶結構。

類成員

//指向鍊錶的頭結點

transient linkedhashmap.entry

head;

//指向鍊錶的尾節點

transient linkedhashmap.entry

tail;

//為false時,遍歷會按插入的順序遍歷

//為true時,每一次get操作,都會把獲得的節點放到鍊錶尾

//預設為false

final

boolean accessorder;

接下來就是分析從增刪查來讀linkedhashmap原始碼。

void

afternodeaccess

(node

p)void

afternodeinsertion

(boolean evict)

void

afternoderemoval

(node

p)

這三個方法是父類hashmap留給子類實現的方法,分別在get、put、remove方法完成後呼叫

1. 新增操作

一開始筆者想找put方法,但發現其並沒有重寫父類的put方法,轉去找entry類在**使用到。找到以下兩個方法。

node

newnode

(int hash, k key, v value, node

e)//紅黑樹結構時用到

treenode

newtreenode

(int hash, k key, v value, node

next)

上面兩個方法是重寫父類的,父類hashmap的put方法中,如果是乙個當前不存在的key,就會根據不同結構分別呼叫上面兩個方法來建立新節點,這樣就能把父類hashmap裡的節點換成linkhashmap中的通過「改裝」的節點了。

接下來看linknodelast()方法操作實現鍊錶

private

void

linknodelast

(linkedhashmap.entry

p)}

就是把新增的節點放在鍊錶最後,如果鍊錶一開始為空,那就賦值給頭結點

再看看afternodeinsertion()方法

void

afternodeinsertion

(boolean evict)

}

由於removeeldestentry()方法總是返回false,所以該方法等於沒有做任何操作。

小總結linkedhashmap的新增操作通過父類hashmap來完成,它則是通過定以義乙個entry繼承父類node的,然後利用entry實現了鍊錶的結構。

2. 查操作

2.1 get操作

public v get

(object key)

getnode()方法在父類hashmap中實現了,linkedhashmap重用其來查詢資料,然後根據accessorder的值來決定是否需要調整鍊錶.

下面看afternodeaccess()方法的做法

void

afternodeaccess

(node

e) tail = p;

//尾節點賦值為p

++modcount;

}}

afternodeaccess()方法做的就是,把傳入節點e,移動到鍊錶尾部。

2.2 遍歷操作來看看其遍歷如何實現,挑entryset方法來說,先回顧下遍歷寫法

iterator it = map.

entryset()

.iterator()

;while

(it.

hasnext()

) it.

next()

;

追蹤其原始碼如下

public set

>

entryset()

public

final iterator

>

iterator()

final

class

linkedentryiterator

extends

linkedha****erator

implements

iterator

>

}

可以看到map.entryset().iterator()這一句**返回的是linkedentryiterator物件。而其next()方法,則是呼叫了nextnode()方法,該方法在父類linkedha****erator中實現了

linkedha****erator()

final linkedhashmap.entry

nextnode()

可以看到遍歷如前文所說,是遍歷鍊錶。

3. 刪除操作

linkedhashmap沒有重寫remove方法,而是重寫了afternoderemoval方法

void

afternoderemoval

(node

e)

linkedhashmap重用了hashmap的remove方法,然後在afternoderemoval方法中刪除鍊錶中相應的節點

利用linkedhashmap的資料結構特性,可以簡便地實現lru演算法。

class

lrucache

public

intget

(int key)

public

void

put(

int key,

int value)

data.

put(key,value);}

}

這裡只展示了實現插入整數,可改進為泛型使其更加通用。

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