LinkedHashMap是如何組織資料的

2021-07-25 17:09:04 字數 4368 閱讀 9652

linkedhashmap繼承自hashmap,底層仍然是陣列加鍊表,除了發生衝突後的單鏈表,它還維護了乙個鏈結所有元素的雙鏈表,這樣就能記錄元素的插入或者訪問順序了。所以linkedhashmap可以做到有序迭代,也可以作為lru演算法的基石。

linkedentryheader;

static class

linkedentry

extends

hashmapentry

/** create a normal entry */

linkedentry(k key, v value, int hash, hashmapentrynext,

linkedentrynxt, linkedentryprv)

}

linkedentry繼承自hashmapentry

next屬性仍然組織發生衝突後的單鏈表。

nxt和prv兩個屬性組織乙個所有元素的雙鏈表。這樣就能記錄插入順序或者訪問順序。

header是雙向迴圈鍊錶的起點,和hashmap中的entryfornullkey一樣,它游離於table之外。

linkedhashmap其實儲存了兩套邏輯,一套是原封不動的hashmap的邏輯。

另一套是乙個雙向鍊錶的邏輯。

linkedhashmap並沒有重寫hashmap的put方法,而只是重寫了其中最後的addnewentry方法。

因為除了組織雙向鍊錶的邏輯,其他地方都和hashmap一樣。

void addnewentry(k key, v value, int hash, int

index)

// create new entry, link it on to list, and put it into table

linkedentryoldtail = header.prv;

linkedentrynewtail = new linkedentry(

key, value, hash, table[index], header, oldtail);

table[index] = oldtail.nxt = header.prv = newtail;

}

第叉叉行,無非也就是乙個雙向鍊錶的插入方法。如果這個過程不熟悉,去看一linkedlist裡的add方法就豁然開朗了。

linkedhashmap的預設順序是插入順序,如果要實現訪問順序,那麼需要將全域性的accessorder屬性置為true。

當然linkedhashmap提供了帶accessorder引數的建構函式。訪問順序是在呼叫get等方法的時候內部呼叫了maketail方法,

非常直觀,也就是把要訪問的entry放到尾部去。

private void maketail(linkedentrye)
maketail方法分兩步實現,第一是把元素取出來,第二是插入到尾部。雖然這樣寫非常像一段台詞,

但實際情況就是這樣

get方法每次都呼叫,put方法中如果key相同會替換掉value,在替換之前會呼叫premodify方法,

premodify在linkedhashmap中的實現是呼叫這個方法

關於雙向鍊錶的刪除和插入操作,請看。

public class

linkedhashmap

extends

hashmap

// 指定容量

public linkedhashmap(int initialcapacity)

// 指定容量和載入因子,內部呼叫三個引數的建構函式。

// 三個引數的構造函式呼叫 super(initialcapacity, loadfactor) 也就是hashmap的建構函式

// loadfactor會被忽略掉,然後自動使用0.75的。

public linkedhashmap(int initialcapacity, float loadfactor)

// 呼叫hashmap的構造方法,來構造table陣列

public linkedhashmap(int initialcapacity, float loadfactor, boolean accessorder)

@override void init()

// 雙向鍊錶的資料結構,這個感覺和linkedlist的雙向鍊錶感覺感謝

static class

linkedentry

extends

hashmapentry

/** create a normal entry */

linkedentry(k key, v value, int hash, hashmapentrynext,

linkedentrynxt, linkedentryprv)

}// 這個this是什麼意思

final k key;

v value;

final int hash;

hashmapentrynext;

hashmapentry(k key, v value, int hash, hashmapentrynext)

/*** returns the eldest entry in the map, or if the map is empty.

* @hide

*/public entryeldest()

// 新add的是在尾部

@override void addnewentry(k key, v value, int hash, int index)

// create new entry, link it on to list, and put it into table

linkedentryoldtail = header.prv;

linkedentrynewtail = new linkedentry(

key, value, hash, table[index], header, oldtail);

table[index] = oldtail.nxt = header.prv = newtail;

}@override void addnewentryfornullkey(v value)

// create new entry, link it on to list, and put it into table

linkedentryoldtail = header.prv;

linkedentrynewtail = new linkedentry(

null, value, 0, null, header, oldtail);

entryfornullkey = oldtail.nxt = header.prv = newtail;

}/**

* as above, but without eviction.

*/@override hashmapentryconstructornewentry(

k key, v value, int hash, hashmapentrynext)

/***

* @param key

* the key.

*/// get方法複寫

@override public v get(object key)

int hash = collections.secondaryhash(key);

// 索引和hashmap一樣

hashmapentry tab = table;

for (hashmapentrye = tab[hash & (tab.length - 1)];

e != null; e = e.next)

}return

null;

}/**

* relinks the given entry to the tail of the list. under access ordering,

* this method is invoked whenever the value of a pre-existing entry is

* read by map.get or modified by map.put.

*/private void maketail(linkedentrye)

@override void premodify(hashmapentrye)

}@override void postremove(hashmapentrye)

// public void clear()

// 回歸到初始的空map狀態

header.nxt = header.prv = header;

}}

LinkedHashMap 是如何實現的

linkedhash 底層基於 hashmap 實現並擴充套件了 hashmap.node 使其支援雙向鍊錶 示例 hashmaphashmap new hashmap linkedhashmaplinkedhashmap new linkedhashmap for int i 0 i 10 i s...

LinkedHashMap簡單解析

原始碼版本1.7 本文參考 1 內部結構 節點的結構 整體結構 插入過程 1 從table的角度看,新的entry需要插入到對應的bucket裡,當有雜湊衝突時,採用頭插法將新的entry插入到衝突鍊錶的頭部。2 從header的角度看,新的entry需要插入到雙向鍊錶的尾部。刪除過程 1 從tab...

LinkedHashMap學習筆記

概述linkedhashmap資料結構相比較於hashmap來說,新增了雙向指標,分別指向前乙個節點 before和後乙個節點 after,從而將所有的節點已鍊錶的形式串聯一起來 hashmap裡面的方法在linkedhashmap進行了重寫 void afternodeaccess nodep v...