Java源碼分析-LinkedHashMap

LinkedHashMap繼承自HashMap,同時(shí)也維護(hù)了元素的插入順序。內(nèi)部多了一個(gè)雙向循環(huán)鏈表的維護(hù),該鏈表是有序的,可以按元素插入順序或元素最近訪問順序(LRU)排列。來(lái)看下源碼吧。

支持原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。

LinkedHashMap是一個(gè)維護(hù)了一個(gè)雙向鏈表的HashMap:


圖片來(lái)自網(wǎng)絡(luò).jpg

繼承關(guān)系

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>

LinkedHashMap繼承自HashMap,最好先看下HashMap的源碼。

內(nèi)部節(jié)點(diǎn)

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

Entry繼承自HashMap.Node,同時(shí)增加了指向前一個(gè)和后一個(gè)節(jié)點(diǎn)的引用。

成員變量

    transient LinkedHashMap.Entry<K,V> head;   //鏈表頭結(jié)點(diǎn)

    /**
     * The tail (youngest) of the doubly linked list.
     */
    transient LinkedHashMap.Entry<K,V> tail;  //鏈表尾節(jié)點(diǎn)
 
    final boolean accessOrder;                 //是否開啟最近最久未使用算法

構(gòu)造函數(shù)

    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

主要的工作是設(shè)置accessOrder這個(gè)成員變量,其他的交給父類構(gòu)造函數(shù)。

核心方法

eldest方法

public Entry<K, V> eldest() {
    LinkedEntry<K, V> eldest = header.nxt;
    return eldest != header ? eldest : null;
}

該方法返回的就是鏈表頭部的節(jié)點(diǎn)。頭結(jié)點(diǎn)代表最久未訪問的節(jié)點(diǎn)。
看下get方法:

@Override public V get(Object key) {
    /*
     * This method is overridden to eliminate the need for a polymorphic
     * invocation in superclass at the expense of code duplication.
     */
    if (key == null) {
        HashMapEntry<K, V> e = entryForNullKey;
        if (e == null)
            return null;
        if (accessOrder)
            makeTail((LinkedEntry<K, V>) e);
        return e.value;
    }

    int hash = Collections.secondaryHash(key);
    HashMapEntry<K, V>[] tab = table;
    for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];   
            e != null; e = e.next) {       //遍歷鏈表
        K eKey = e.key;
        if (eKey == key || (e.hash == hash && key.equals(eKey))) {  //若找到
            if (accessOrder)
                makeTail((LinkedEntry<K, V>) e);    //將當(dāng)前節(jié)點(diǎn)放到鏈表尾部
            return e.value;   //返回節(jié)點(diǎn)的值
        }
    }
    return null;
}

該方法先計(jì)算Hash值,然后根據(jù)Hash值確定桶,遍歷桶中的節(jié)點(diǎn),若找到,則返回該節(jié)點(diǎn)的值,并將該節(jié)點(diǎn)放到鏈表的末尾。所以頭結(jié)點(diǎn)就是最久為訪問的節(jié)點(diǎn)。
看張圖就清楚了:

圖片來(lái)自網(wǎng)絡(luò).jpg

這張圖中,我們先刪除了節(jié)點(diǎn)3,然后插入了節(jié)點(diǎn)6,接著訪問節(jié)點(diǎn)4,訪問時(shí)會(huì)先刪除節(jié)點(diǎn)4,并將節(jié)點(diǎn)4放入鏈表的末尾。

總結(jié)

LinkedHashMap實(shí)現(xiàn)了HashMap的快速訪問,同時(shí)也按訪問順序或插入順序維護(hù)了雙向鏈表。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容