聊聊LinkedHashMap

LinkedHashMap簡介

LinkedHashMap是一個根據某種規則有序的hashmap。根據名字,咱們也能夠看出這個集合是有hash散列的功能的同時也有順序。hashmap是沒法根據某種順序來訪問數據的,例如放入集合的元素前後的順序。list都有這個功能,能夠根據放入集合的前後來訪問具體的數據。這裏你們也確定是有疑問的,例如都已經使用了hash了,爲何還要去保證順序訪問。這個在後面的場景中解釋。java

LinkedHashMap的實現

當剛遇到這個集合的時候,我也疑惑,能同時知足條件的數據結構到底是怎麼樣的。若是沒有思考這個問題,還請看到這裏好好想一想。 ---------滑稽分割-------- 答案確實是沒有這樣的數據結構。他是兩種結構的組合。一種是咱們熟悉的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

相關文章
相關標籤/搜索