Java LinkedHashMap工做原理及實現

文章轉載自http://www.importnew.com/18706.html

 

1. 概述

在理解了#7 介紹的HashMap後,咱們來學習LinkedHashMap的工做原理及實現。首先仍是相似的,咱們寫一個簡單的LinkedHashMap的程序:html

1node

2git

3github

4app

5函數

6post

7學習

8spa

93d

10

11

12

LinkedHashMap<String, Integer> lmap = new LinkedHashMap<String, Integer>();

lmap.put("語文", 1);

lmap.put("數學", 2);

lmap.put("英語", 3);

lmap.put("歷史", 4);

lmap.put("政治", 5);

lmap.put("地理", 6);

lmap.put("生物", 7);

lmap.put("化學", 8);

for(Entry<String, Integer> entry : lmap.entrySet()) {

    System.out.println(entry.getKey() + ": " + entry.getValue());

}

運行結果是:

1

2

3

4

5

6

7

8

語文: 1

數學: 2

英語: 3

歷史: 4

政治: 5

地理: 6

生物: 7

化學: 8

咱們能夠觀察到,和HashMap的運行結果不一樣,LinkedHashMap的迭代輸出的結果保持了插入順序。是什麼樣的結構使得LinkedHashMap具備如此特性呢?咱們仍是同樣的看看LinkedHashMap的內部結構,對它有一個感性的認識:

沒錯,正如官方文檔所說:

Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked listrunning through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).

LinkedHashMap是Hash表和鏈表的實現,而且依靠着雙向鏈表保證了迭代順序是插入的順序。

2. 三個重點實現的函數

在HashMap中提到了下面的定義:

1

2

3

4

// Callbacks to allow LinkedHashMap post-actions

void afterNodeAccess(Node<K,V> p) { }

void afterNodeInsertion(boolean evict) { }

void afterNodeRemoval(Node<K,V> p) { }

LinkedHashMap繼承於HashMap,所以也從新實現了這3個函數,顧名思義這三個函數的做用分別是:節點訪問後、節點插入後、節點移除後作一些事情。

afterNodeAccess函數

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

void afterNodeAccess(Node<K,V> e) { // move node to last

    LinkedHashMap.Entry<K,V> last;

    // 若是定義了accessOrder,那麼就保證最近訪問節點放到最後

    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;

        if (last == null)

            head = p;

        else {

            p.before = last;

            last.after = p;

        }

        tail = p;

        ++modCount;

    }

}

就是說在進行put以後就算是對節點的訪問了,那麼這個時候就會更新鏈表,把最近訪問的放到最後,保證鏈表。

afterNodeInsertion函數

1

2

3

4

5

6

7

8

void afterNodeInsertion(boolean evict) { // possibly remove eldest

    LinkedHashMap.Entry<K,V> first;

    // 若是定義了移除規則,則執行相應的溢出

    if (evict && (first = head) != null && removeEldestEntry(first)) {

        K key = first.key;

        removeNode(hash(key), key, null, false, true);

    }

}

若是用戶定義了removeEldestEntry的規則,那麼即可以執行相應的移除操做。

afterNodeRemoval函數

1

2

3

4

5

6

7

8

9

10

11

12

13

14

void afterNodeRemoval(Node<K,V> e) { // unlink

    // 從鏈表中移除節點

    LinkedHashMap.Entry<K,V> p =

        (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;

    p.before = p.after = null;

    if (b == null)

        head = a;

    else

        b.after = a;

    if (a == null)

        tail = b;

    else

        a.before = b;

}

這個函數是在移除節點後調用的,就是將節點從雙向鏈表中刪除。

咱們從上面3個函數看出來,基本上都是爲了保證雙向鏈表中的節點次序或者雙向鏈表容量所作的一些額外的事情,目的就是保持雙向鏈表中節點的順序要從eldest到youngest。

3. put和get函數

put函數在LinkedHashMap中未從新實現,只是實現了afterNodeAccessafterNodeInsertion兩個回調函數。get函數則從新實現並加入了afterNodeAccess來保證訪問順序,下面是get函數的具體實現:

1

2

3

4

5

6

7

8

public V get(Object key) {

    Node<K,V> e;

    if ((e = getNode(hash(key), key)) == null)

        return null;

    if (accessOrder)

        afterNodeAccess(e);

    return e.value;

}

值得注意的是,在accessOrder模式下,只要執行get或者put等操做的時候,就會產生structural modification。官方文檔是這麼描述的:

A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.

不要犯了像ConcurrentModificationException with LinkedHashMap相似的問題。

總之,LinkedHashMap不愧是HashMap的兒子,和老子太像了,固然,青出於藍而勝於藍,LinkedHashMap的其餘的操做也基本上都是爲了維護好那個具備訪問順序的雙向鏈表

相關文章
相關標籤/搜索