LinkedHashMap

1、開始
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
繼承了類HashMap,實現了Map接口

2、屬性

    //雙向鏈表,用於記錄全部的元素
    private transient Entry<K,V> header;

    //遍歷順序【訪問順序或插入順序】,默認插入順序
    private final boolean accessOrder;


3、雙向鏈表

     private static class Entry<K,V> extends HashMap.Entry<K,V> {
         //雙向鏈表中的上一個節點before和下一個節點after
        Entry<K,V> before, after;

        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
            super(hash, key, value, next);
        }

        //從雙向鏈表中刪除元素
        private void remove() {
            //改變當前節點的先後兩個節點的引用關係,若當前節點沒有被引用,則才能夠被GC回收
            //將前一個節點的after指向後一個節點
            before.after = after;
            //將後一個節點的before指向前一個節點
            after.before = before;
        }

        //將當前節點插入到指定節點的鏈表中,即指定節點的前面
        private void addBefore(Entry<K,V> existingEntry) {
            //指定當前節點與先後節點的引用關係
            //將當前節點的後一個節點指向指定節點
            after  = existingEntry;
            //將當前節點的前一個節點指向指定節點的前一個節點
            before = existingEntry.before;

            //指定先後節點與當前節點的引用關係
            //當前節點的前一個節點的後一個節點就是當前節點
            before.after = this;
            //當前節點的後一個節點的前一個節點就是當前節點
            after.before = this;
        }

           //查詢或修改元素時調用
        void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                //當時按訪問順序時,即最近較少使用順序LRU
                lm.modCount++;
                //刪除當前節點
                remove();
                //噹噹前節點添加到鏈表尾部
                addBefore(lm.header);
            }
        }

        //刪除元素時調用
        void recordRemoval(HashMap<K,V> m) {
            remove();
        }
    }

4、構造器

    //指定容量和加載因子,遍歷順序爲插入順序
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }
    //默認加載因子,遍歷順序爲插入順序
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }
    //默認初始化容量和加載因子,遍歷順序爲插入順序
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }
    //添加元素用於初始化,遍歷順序爲插入順序
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super(m);
        accessOrder = false;
    }
    //指定容量和加載因子,以及遍歷順序
    public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

    //構造對象時,初始化雙向鏈表
    @Override
    void init() {
        //初始化頭節點
        header = new Entry<>(-1, null, null, null);
        //頭結點便是其自身的前一個也是後一個
        header.before = header.after = header;
    }

5、添加

    //添加時,重寫了HashMap的此方法
     void addEntry(int hash, K key, V value, int bucketIndex) {
        super.addEntry(hash, key, value, bucketIndex);

        //頭結點的第一個節點
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            //刪除第一個節點
            removeEntryForKey(eldest.key);
        }
    }

    //新增節點
    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++;
    }

    //是否刪除第一個節點,即老的節點
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

6、查找

    public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key);
        if (e == null)
            return null;
        //記錄查找的元素,用於根據訪問的順序時,維護雙向鏈表
        e.recordAccess(this);
        return e.value;
    }

參考資料:
http://www.cnblogs.com/tstd/p/5059589.html
相關文章
相關標籤/搜索