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