1. 程式人生 > >基礎資料結構之LinkedHashMap原始碼分析

基礎資料結構之LinkedHashMap原始碼分析

1.LinkedHashMap資料結構是雙向迴圈連結串列

 LinkedHashMap節點中得知相關內容,Node節點中存在before,after,雙向連結串列特性

 原始碼如下

/**
* LinkedHashMap entry.
*/
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);
}


e = header; e != header ;e = e.after 迴圈連結串列特性

原始碼如下:

public boolean containsValue(Object value) {
        // Overridden to take advantage of faster iterator
        if (value==null) {
            for (Entry e = header.after; e != header; e = e.after)//是否包含value,遍歷整個連結串列檢視元素是否存在
                if (e.value==null)
                    return true;
        } else {
            for (Entry e = header.after; e != header; e = e.after)
                if (value.equals(e.value))
                    return true;
        }
        return false;
    }


 LinkedHashMap初始化原始碼如下:

 /**
     * Called by superclass constructors and pseudoconstructors (clone,
     * readObject) before any entries are inserted into the map.  Initializes
     * the chain.
     */
    void init() {
        header = new Entry<K,V>(-1, null, null, null);
        header.before = header.after = header; //一個節點前驅指標和後繼指標都指向自己
    }


2.LinkedHashMap新增新元素

 /**
     * This override alters behavior of superclass put method. It causes newly
     * allocated entry to get inserted at the end of the linked list and
     * removes the eldest entry if appropriate.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        createEntry(hash, key, value, bucketIndex);//陣列中索引放入元素 && 新元素插入到雙向迴圈連結串列中
        // Remove eldest entry if instructed, else grow capacity if appropriate
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {         //元素相同,移除old Entry元素
            removeEntryForKey(eldest.key);
        } else { 
            if (size >= threshold)                     //如果有效元素size > 擴容因子*size 
                resize(2 * table.length);              //按照兩倍大小容量擴容
        }
    }

    /**
     * This override differs from addEntry in that it doesn't resize the
     * table or remove the eldest entry.
     */
    void createEntry(int hash, K key, V value, int bucketIndex) {
        HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<K,V>(hash, key, value, old);//建立一個新的Entry節點
        table[bucketIndex] = e;                             //新的Entry節點,放入到table陣列中,table陣列是HashMap類的屬性
        e.addBefore(header);                                //新的Entry節點,插入到雙向迴圈連結串列中
        size++;                                             //有效元素大小+1
    }

3.LinkedHashMap獲取訪問元素特性

   public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key); //呼叫父類HashMap方法獲取元素
        if (e == null)
            return null;
        e.recordAccess(this);       //訪問後,對該訪問痕跡進行記錄,然後重新排序。從而實現LRU淘汰最久未使用的元素
        return e.value;
    }

      /**
         * 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) {     //如果打開了accessOrder開關
                lm.modCount++;     //訪問記錄modCount自增1
                remove(); 
                addBefore(lm.header);     //訪問的元素,前面移動
            }
        }

     優化後的程式碼

   public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key);
        if (e == null)
            return null;
       if(e.accessOrder) //如果打開了accessOrder開關,進行排序。可以省略強制轉化的效率
        e.recordAccess(this);
        return e.value;
    }

總結:

   1.資料結構特性可以疊加使用。陣列特性增加連結串列特性,可以進行擴容元素屬性。