1. 程式人生 > >LinkedHashMap源碼淺析jdk1.7

LinkedHashMap源碼淺析jdk1.7

add sting div tee 功能 use sso 是否 初始化

LinkedHahsMap的繼承關系

技術分享圖片

LinkedHashMap直接繼承了HahsMap,而linkedHashMap和HashMap在同一個包下,因此HashMap中所有的非private的屬性都能拿過來直接用。

LinkedHashMap繼承HashMap原來的功能同時進行了修改。主要對原來Entry的結構進行了擴展,在繼承父類Entry的基礎上,有添加的兩個屬性Entry<K,V> before, after;和addBefore方法。同時覆蓋了父類的init,addEntry,createEntry,transfer等方法,添加了header成員變量。

 private
transient Entry<K,V> header;
private static class Entry<K,V> extends HashMap.Entry<K,V> {
        // These fields comprise the doubly linked list used for iteration.
        Entry<K,V> before, after;

        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
            
super(hash, key, value, next); } /** * Removes this entry from the linked list. */ private void remove() { before.after = after; after.before = before; } /** * Inserts this entry before the specified existing entry in the list.
*/ private void addBefore(Entry<K,V> existingEntry) { after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; } /** * This method is invoked by the superclass whenever the value * of a pre-existing entry is read by Map.get or modified by Map.set. * If the enclosing Map is access-ordered, it moves the entry * to the end of the list; otherwise, it does nothing. */ void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } } void recordRemoval(HashMap<K,V> m) { remove(); } }

LinkedHashMap的初始化

linkedHashMap所有的構造方法裏都調用了父類相關的構造方法,在父類構造中有調用了init方法,而linkedHashMap又覆蓋了init方法,因此初始化先執行父類相關的操作,在執行自己init方法

@Override
    void init() {
        header = new Entry<>(-1, null, null, null);
        header.before = header.after = header;
    }

init方法主要是將header實例化,實例化之後就會出現一個Entry類型的header的指針,其before和after都指向自己,如下圖所示

技術分享圖片

LinkedHashMap put操作

linkedHashMap沒有覆蓋put方法,還是用父類的,因此調用父類的put會完成table屬性的初始化,以及計算元素在table中的索引(調用的都是父類相關方法),然後調用addEntry方法,這時會調用自己的addEntry方法,因為linkedHashMap重寫了addEntry方法

 void addEntry(int hash, K key, V value, int bucketIndex) {
// 調用父類的addEntry
        super.addEntry(hash, key, value, bucketIndex);

        // Remove eldest entry if instructed
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        }
    }

在自己的addEntry方法裏面又調用了父類的方法,父類的方法如下:

void addEntry(int hash, K key, V value, int bucketIndex) {
//看是否需要擴容
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
        // 又調用createEntry
        createEntry(hash, key, value, bucketIndex);
    }

addEntry方法裏有調用createEntry,同樣linkedHashMap覆蓋了父類的createEntry,調用本地的

void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}

把entry添加到數組裏面後,有調用了entry的addBefore方法

 private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }

addBefore傳進來的是header,進行如下操作

1. after  = existingEntry;

把當前節點(比如是A)的after指向header(existingEntry傳遞的都是header), 因此A.after--->header

2. before = existingEntry.before;

當前節點的before指向 header所指向的before(header.before=B),A.before---->B

3. before.after = this;

也就是 B.after---->A

4. after.before = this;

相當於header.before--->A

如果是第一次添加,上面的B就是header對應如下圖

技術分享圖片

linkedHashMap的Entry之間按照元素的put的先後順序形成了雙向循環鏈表,hashMap中元素與元素沒有先後順序,沒法知道元素的put先後順序,而linkedHashMap每次添加元素時都能通過header找到上一次添加的元素,並建立各元素之間的聯系。

LinkedHashMap和HashMap的結構的比較

linkedHashMap

技術分享圖片

HashMap

技術分享圖片

LinkedHashMap源碼淺析jdk1.7