linkedhashmap繼承了hashmap,他在hashmap的基礎上增加了乙個雙向鍊錶的結構,鍊錶預設維持key插入的順序,重複的key值插入不會改變順序,適用於使用者需要返回乙個順序相同的map物件的情況。還可以生成access-order順序的版本,按照最近訪問順序來儲存,剛被訪問的結點處於鍊錶的末尾,適合lru,put get compute merge都算作一次訪問,其中put key值相同的結點也算作一次訪問,replace只有在換掉乙個鍵值對的時候才算一次訪問,putall產生的訪問順序取決於原本map的迭代器實現。
在插入鍵值對時,可以通過對removeeldestentry重寫來實現新鍵值對插入時自動刪除最舊的鍵值對
擁有hashmap提供的方法,迭代器因為是通過遍歷雙向鍊錶,所以額外開銷與size成正比與capacity無關,因此選擇過大的初始大小對於遍歷時間的增加沒有hashmap嚴重,後者的遍歷時間依賴與capacity。
同樣是非執行緒安全方法,對於linkedhashmap來說,修改結構的操作除了增加和刪除鍵值對外,還有對於access-order時進行了access導致迭代器順序改變,主要是get操作,對於插入順序的來說,僅僅修改乙個已有key值的value值不是乙個修改結構的操作,但對於訪問順序,put和get已有的key值會改變順序。迭代器也是fail-fast設計,但是fail-fast只是乙個除錯功能,乙個設計良好的程式不應該出現這個錯誤
因為hashmap加入了treenode,所以現在linkedhashmap也有這個功能
以下描述中的鍊錶,若無特別說明都是指linkedhashmap的雙向鍊錶
先來看一下基本結構,每個鍵值對加入了前後指標,集合加入了頭尾指標來形成雙向鍊錶,accessorder代表鍊錶是以訪問順序還是插入順序儲存
static class entryextends hashmap.node
}/**
* the head (eldest) of the doubly linked list.頭部
*/transient linkedhashmap.entryhead;
/*** the tail (youngest) of the doubly linked list.尾部
*/transient linkedhashmap.entrytail;
//true訪問順序 false插入順序
final boolean accessorder;
然後是幾個內部方法。linknodelast將p連線到鍊錶尾部
private void linknodelast(linkedhashmap.entryp)
}
transferlinks用dst替換src
private void transferlinks(linkedhashmap.entrysrc,
linkedhashmap.entrydst)
reinitialize在呼叫hashmap方法的基礎上,將head和tail設為null
void reinitialize()
newnode生成乙個linkedhashmap結點,next指向e,插入到linkedhashmap鍊錶末端
nodenewnode(int hash, k key, v value, nodee)
replacementnode根據原結點生成乙個linkedhashmap結點替換原結點
nodereplacementnode(nodep, nodenext)
newtreenode生成乙個treenode結點,next指向next,插入到linkedhashmap鍊錶末端
treenodenewtreenode(int hash, k key, v value, nodenext)
replacementtreenode根據結點p生成乙個新的treenode,next設為給定的next,替換原本的p
treenodereplacementtreenode(nodep, nodenext)
afternoderemoval從linkedhashmap的鏈上移除結點e
void afternoderemoval(nodee)
afternodeinsertion可能移除最舊的結點,需要evict為true同時鍊錶不為空同時removeeldestentry需要重寫
void afternodeinsertion(boolean evict)
}
afternodeaccess在訪問過後將結點e移動到鍊錶尾部,需要map是access-order,若移動成功則增加modcount
void afternodeaccess(nodee)
tail = p;//結點e移動到鍊錶尾部
++modcount;//因為有access-order下結點被移動,所以增加modcount
}}
建構函式方面,accessorder預設是false插入順序,初始大小為16,負載因子為0.75,這裡是同hashmap。複製構造也是呼叫了hashmap.putmapentries方法
containsvalue遍歷鍊錶尋找相等的value值,這個操作一定不會造成結構改變
public boolean containsvalue(object value)
return false;
}
get方法復用hashmap的getnode方法,若找到結點且map是訪問順序時,要將訪問的結點放到鍊錶最後,若沒找到則返回null。而getordefault僅有的區別是沒找到時返回defaultvalue
public v get(object key)
public v getordefault(object key, v defaultvalue)
clear方法在hashmap的基礎上要把head和tail設為null
public void clear()
removeeldestentry在put和putall插入鍵值對時呼叫,原本是一定返回false的,如果要自動刪除最舊的鍵值對要返回true,需要進行重寫。比如下面這個例子,控制size不能超過100
private static final int max_entries = 100;
protected boolean removeeldestentry(map.entry eldest)
下面兩個方法和hashmap相似,返回key的set和value的collection還有返回鍵值對的set,這個是直接引用,所以對它們的remove之類的修改會直接反饋到linkedhashmap上
public setkeyset()
return ks;//返回key值的set
}public collectionvalues()
return vs;//返回乙個包含所有value值的collection
}public set> entryset()
檢查hashmap的putval方法,我們可以看到在找到了相同key值並修改value值時會呼叫afternodeaccess,對於access-order會改變結點順序
if (e != null)
Java LinkedHashMap原始碼解讀
map 介面的雜湊表和鏈結列表實現,具有可預知的迭代順序。此實現與 hashmap 的不同之處在於,後者維護著乙個執行於所有條目的雙重鏈結列表。此鏈結列表定義了迭代順序,該迭代順序通常就是將鍵插入到對映中的順序 插入順序 注意,如果在對映中 重新插入 鍵,則插入順序不受影響。如果在呼叫 m.put ...
azkaban web server原始碼解析
azkaban主要用於hadoop相關job任務的排程,但也可以應用任何需要排程管理的任務,可以完全代替crontab。azkaban主要分為web server 任務上傳,管理,排程 executor server 接受web server的排程指令,進行任務執行 1.資料表 projects 工...
JDK LinkedHashMap原始碼解析
今天來分析一下jdk linkedhashmap的源 public class linkedhashmapextends hashmapimplements map可以看到,linkedhashmap繼承自hashmap,並且也實現了map介面,所以linkedhashmap沿用了hashmap的大...