LinkedHashMap是一個根據某種規則有序的hashmap。根據名字,咱們也能夠看出這個集合是有hash散列的功能的同時也有順序。hashmap是沒法根據某種順序來訪問數據的,例如放入集合的元素前後的順序。list都有這個功能,能夠根據放入集合的前後來訪問具體的數據。這裏你們也確定是有疑問的,例如都已經使用了hash了,爲何還要去保證順序訪問。這個在後面的場景中解釋。java
當剛遇到這個集合的時候,我也疑惑,能同時知足條件的數據結構到底是怎麼樣的。若是沒有思考這個問題,還請看到這裏好好想一想。 ---------滑稽分割-------- 答案確實是沒有這樣的數據結構。他是兩種結構的組合。一種是咱們熟悉的hashmap。另一種就是鏈表。數據存入集合的時候,先根據hashmap的流程存放入數組中。而後再根據鏈表的原則,進行連接。 若是看源碼,也會發現其實沒有多少方法。基本都是繼承自hashmap的。數組
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
咱們來看看串聯邏輯的幾個操做
節點組成緩存
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); } }
能夠看出。相比hashmap的節點。linkedhashmap主要增長before, after。能夠組成一個雙向鏈表。
節點加入數據結構
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { LinkedHashMap.Entry<K,V> last = tail;//獲取最後一個節點 tail = p;//tail指向新加入的節點 if (last == null)//鏈表爲空 head = p; else { p.before = last; last.after = p; } } //新建節點的時候把節點加入了雙向鏈表 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; }
刪除狀況也是相似。
節點訪問code
public V get(Object key) { Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return null; if (accessOrder)//是否根據某種順序 afterNodeAccess(e);//把訪問節點加入到尾節點 return e.value; }
afterNodeAccess中主要是把訪問的節點從原來的位置摘除,加入到尾節點,成爲鏈表的最後一個元素。繼承
順序遍歷和快速定位
LinkedHashMap適合有加入順序和快速定位的場景。我本身開發中遇到過一個場景,就是把配置順序讀取,須要按照讀取的順序訪問,並且還須要根據值key直接獲取值。這個場景就須要使用LinkedHashMap。
緩存
LinkedHashMap另一個強大的功能就是作緩存。不過咱們要繼承一下。去重寫一個方法。隊列
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {//默認是沒有操做 return false; }
這個方法在插入以後會被調用到。開發
void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) {//刪除第一個元素 K key = first.key; removeNode(hash(key), key, null, false, true); } }
LinkedHashMap支持兩種緩存策略。FIFO和LRU。你們應該也猜到控制策略的地方就是accessOrder。默認爲false。就是FIFO。設置爲true時就是LRU。由於在訪問的時候會調整鏈表結構,調用afterNodeAccess會把訪問的節點放入隊列最後。因此每次刪除first就能夠達到效果。我通常會選擇繼承LinkedHashMap。而後重寫removeEldestEntry,例如能夠元素個數達到200範圍true。這裏須要根據具體場景來編寫。rem