LinkedHashMap源碼分析

1、特點

LinkedHashMap有序的,內部維護了一個雙向鏈表

2、LinkedHashMap是如何保證順序的

   2.1 核心屬性

//是否根據操作順序排序
final boolean accessOrder;

//鏈表頭節點
transient LinkedHashMap.Entry<K,V> head;

//鏈表尾節點
transient LinkedHashMap.Entry<K,V> tail;

 

//當accessOrder=true是,LinkedHashMap鏈表順序不是根據插入的順序排序,而是根據操作的順序顯示
@Test
    public void test4(){
        LinkedHashMap<String,String> map = new LinkedHashMap(16,0.75f,true);
        map.put("1","1");
        map.put("2","2");
        map.put("3","3");
        map.get("1");
        map.put("4","4");
        map.put("3","33");
        for(String key : map.keySet()){
            System.out.println(key);
        }
    }

顯示結果爲:2 1 4 3

 2.2、put()方法

/**
 * 1、LinkedHashMap繼承了HashMap
 * 2、put()方法走HashMap的put方法
 * 
 * 改變:
 * 在putVal()方法中,linkedHashMap重寫了newNode()方法
 */

Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
        //創建一個新節點
        LinkedHashMap.Entry<K,V> p =
            new LinkedHashMap.Entry<K,V>(hash, key, value, e);
        linkNodeLast(p);
        return p;
    }

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        //如果尾節點爲空
        if (last == null)
            //則p爲頭節點
            head = p;
        else {
            //如果尾結點不爲空,p的頭結點爲原始的尾結點,原始的尾結點的下一節點爲p
            //這樣就形成了鏈表結構,就有了順序
            p.before = last;
            last.after = p;
        }
    }

3、LinkedHashMap獨特的功能

      linkedHashMap可以根據操作順序排序

void afterNodeAccess(Node<K,V> e) {
        LinkedHashMap.Entry<K,V> last;
        //如果accessOrder=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節點
                last = b;
            //如果last(可以理解爲倒數第二個節點)節點爲空,說明鏈表中只有一個元素,設置頭結點爲p
            if (last == null)
                head = p;
            else {
                //更新當前節點的前節點爲last,last的尾結點爲p
                p.before = last;
                last.after = p;
            }
            //設置尾結點爲p
            tail = p;
            //更新操作次數
            ++modCount;
        }
    }

 

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