HashMap 是無序的kv鍵值對容器,TreeMap 則是根據key進行排序的kv鍵值對容器,而LinkedHashMap一樣也是一個有序的kv鍵值對容器,區別是其排序方式依據的是進入Map的前後順序java
LinkedHashMap
繼承自 HashMap
, 直接看其內部方法,並無覆蓋HashMap
的增刪查詢接口,連tables數組也沒有從新覆蓋,因此數據結構基本沒啥變化node
首先看繼承體系以下編程
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
看到這裏,有個地方比較有意思,HashMap 既然已經實現了Map接口,爲何 LinkedHashMap
也要另外實現 Map
接口?數組
HashMap
類,必然是實現了Map
接口的從我的角度觸發,這應該是一種編程習慣的問題數據結構
一樣從put(k,v)
方法出發,經過查看新增一個kv對,數據是如何保存的來肯定數據存儲結構,由於 LinkedHashMap
並無覆蓋 put()
方法,因此能夠肯定底層的存儲結構一致,那麼有序是如何保證的呢?學習
查看源碼,發現新增了兩個成員.net
/** * The head (eldest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> head; /** * The tail (youngest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> tail; static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
上面兩個維護的是一個雙向鏈表的頭尾,這個鏈表根據插入Map的順序來維護Node節點的,以此保證了順序code
既然LinkedHashMap
在HashMap
的基礎上維護了一個雙向鏈表,那麼這個鏈表的增刪修改的邏輯是怎樣的?對象
LinkedHashMap
擴展了 Entry類,新增了before, after
, 分別指向該節點在鏈表中的先後節點blog
新建立一個節點
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e); // 將新增的節點放在鏈表的最後面 linkNodeLast(p); return p; }
依然以put(k,v)
做爲研究對象,分析鏈表的關係維護
主要方法: java.util.HashMap#putVal
當插入已經存在的kv對時,不會建立新的Node節點,而會調用下面的方法
void afterNodeAccess(Node<K,V> e) { // move node to last LinkedHashMap.Entry<K,V> last; if (accessOrder && (last = tail) != e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; p.after = null; if (b == null) head = a; else b.after = a; if (a != null) a.before = b; else last = b; if (last == null) head = p; else { p.before = last; last.after = p; } tail = p; ++modCount; } }
accessOrder
true表示鏈表的順序根據訪問順序來,false表示根據插入順序來
默認會設置爲false,此時上面的邏輯基本上不走到,即表示插入一個已存在的kv對,不會修改鏈表的順序
若是顯示設置 accessOrder
爲true,則會將修改的節點,放在鏈表的最後
新增一個不存在的kv對,首先是調用上面的方法,建立一個Node節點: LinkedHashMap.Entry<K,V>
, 在建立節點的同時,就已經將節點放在了鏈表的最後, 實現邏輯以下
// link at the end of list private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { LinkedHashMap.Entry<K,V> last = tail; tail = p; if (last == null) head = p; else { p.before = last; last.after = p; } }
同上
LinkedHashMap
存儲結構和 HashMap
相同,依然是數組+鏈表+紅黑樹LinkedHashMap
額外持有一個雙向鏈表,維護插入節點的順序掃一掃二維碼,關注小灰灰blog