Java-Collection源碼分析(八)——LinkedHashMap

一、LinkedHashMap數據結構

LinkedHashMap是建立在HashMap的數組、鏈表和紅黑樹的基礎上,添加了一個雙向循環列表,將HashMap中的元素鏈接起來。

    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中的next是用於維護HashMap指定table位置上連接的node的順序的。


before、after是用於維護Entry(繼承自HashMap中的Node)插入的先後順序的。


二、底層操作

2.1 linkNodeLast():

    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;
        }
    }

2.2 transferLinks():

應用src鏈接到dst,用dst替換src。

    private void transferLinks(LinkedHashMap.Entry<K,V> src, LinkedHashMap.Entry<K,V> dst) {
        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
        if (b == null)
            head = dst;
        else
            b.after = dst;
        if (a == null)
            tail = dst;
        else
            a.before = dst;
    }

2.3 afterNodeRemoval():

取消鏈接節點,但是沒有刪除節點,不利於JVM進行垃圾回收

    void afterNodeRemoval(Node<K,V> e) {
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        p.before = p.after = null;
        if (b == null)
            head = a;
        else
            b.after = a;
        if (a == null)
            tail = b;
        else
            a.before = b;
    }

2.4 afterNodeInsertion()

可能刪除長者

    void afterNodeInsertion(boolean evict) { 
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }

2.5 afterNodeAccess()

將節點移動到最後
    void afterNodeAccess(Node<K,V> e) { 
        LinkedHashMap.Entry<K,V> last;
        //若訪問順序爲true,且訪問的對象不是尾結點
        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;
        }
    }

三、實現的主要方法

通過調用底層操作完成。

    //如果此映射將一個或多個鍵映射到指定的值,則返回true。
    public boolean containsValue(Object value) {
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            V v = e.value;
            if (v == value || (value != null && value.equals(v)))
                return true;
        }
        return false;
    }
    //返回指定鍵映射到的值,如果此映射不包含鍵的映射,則返回null。
    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;
    }
    //返回指定鍵映射到的值,如果此映射不包含鍵的映射,則返回defaultValue。
    public V getOrDefault(Object key, V defaultValue) {
       Node<K,V> e;
       if ((e = getNode(hash(key), key)) == null)	//調用父類HashMap中的getNode方法
           return defaultValue;
       if (accessOrder)
           afterNodeAccess(e);
       return e.value;
   }
    //從此地圖中刪除所有的映射。
    public void clear() {
        super.clear();
        head = tail = null;
    }
    //如果此地圖應刪除其最老的條目,則返回true。
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }
}




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