LinkedHashMap源碼筆記(jdk8)

需先看HashMap源碼:https://blog.csdn.net/yzh_1346983557/article/details/105456563

一、LinkedHashMap的成員變量

    //雙向鏈表的頭結點
    transient LinkedHashMap.Entry<K,V> head;

    //雙向鏈表的尾結點
    transient LinkedHashMap.Entry<K,V> tail;

    //排序方式,true-訪問順序 false-插入順序
    //默認是插入順序存儲:accessOrder = false;
    //accessOrder = true時表示訪問順序存儲,就是最新訪問的數據會放到鏈表尾部!(訪問順序的LinkedHashMap進行了get操作以後,重新排序,把get的Entry移動到雙向鏈表的表尾。)
    final boolean accessOrder;

LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>,可發現LinkedHashMap相比較HashMap多維護了2個成員變量head、tail,這2個變量就是LinkedHashMap實現雙向鏈表的關鍵變量。

二、LinkedHashMap的靜態內部類Entry

    static class Entry<K,V> extends HashMap.Node<K,V> {
        //新加成員變量before、after,用於雙向鏈表的連接
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

也是比HashMap.Node多維護了2個成員變量before、after,用於雙向鏈表的連接。

三、LinkedHashMap的newNode()方法

    //HashMap.put()方法創建新Node會調用newNode()方法,LinkedHashMap重寫了HashMap的newNode()
    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;
    }

    //將新節點加入雙向鏈表尾部
    // 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;//舊尾節點作爲新節點的before
            last.after = p;//新節點作爲舊尾節點的after
        }
    }

HashMap.put()方法創建新Node會調用newNode()方法,LinkedHashMap重寫了HashMap的newNode()。所以,往LinkedHashMap中put()數據時會調用linkNodeLast(),將新節點加入雙向鏈表。

jdk1.7是在構造函數中調用init()方法,init()中直接new Entry()創建了一個空節點對象作爲雙向鏈表的初始節點。jdk1.8去除了這一操作,沒有去new一個空節點作爲鏈表初始節點,這樣,鏈表中維護的節點就都是LinkedHashMap中實際存在的對象了。

四、LinkedHashMap.forEach()數據迭代方法

    public void forEach(BiConsumer<? super K, ? super V> action) {
        if (action == null)
            throw new NullPointerException();
        int mc = modCount;
        //從雙向鏈表的head開始,依次after迭代。所以取數據和存數據順序能相同。
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            action.accept(e.key, e.value);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }

五、LinkedHashMap的數據結構圖

圖來源(侵權刪):https://www.jianshu.com/p/8f4f58b4b8ab

實際上圖是jdk1.7的LinkedHashMap的數據結構,jdk1.8中Entry header就是Entry1,偷懶拿來用一下。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章