LinkedHashMap core source code analysis

Once people recognize themselves, they are not so gregarious.
—— "Mid-level Collection"

0 Preface

Unordered HashMap, TreeMap sorted by key, so what are the characteristics of LinkedHashMap-maintaining the order of insertion. LinkedHashMap is also from Bloch (the man who developed the entire Java collection framework).

  • Element storage relationship

    Red and yellow arrows: order of adding elements
    Blue arrows: storage order of each element of a single linked list
    head: linked list head
    tail: linked list tail

1 Inheritance system

  • Inherited from HashMap, so it also has the glory of HashMap.
    5088755_1577812744625_DA615EAF7757A05A68BDC4C9093BBBD8

2 Properties

  • Head of doubly linked list (oldest)

  • End of doubly linked list (minimum)

  • Subclass of HashMap.Node: Regular LinkedHashMap node, adding before and after attributes to maintain the structure of doubly linked list

  • Iterative sorting method of this LinkedHashMap:
    true: access order
    false (default): insertion order

3 Construction method

The constructors are the constructors that first execute the parent class HashMap.

3.1 No parameters

  • Construct an empty LinkedHashMap instance that maintains the insertion order, its default initial capacity (16) and load factor (0.75).

3.2 Participation

  • Construct an empty LinkedHashMap instance, you can specify the initial capacity, load factor and sorting mode.
  • Construct a LinkedHashMap instance that maintains the insertion order. The instance has the same mapping relationship as the specified map. The LinkedHashMap instance created has a default load factor (0.75) and an initial capacity sufficient to accommodate the map in the specified map.

Below we begin to study how the main features of this class are implemented through code.

4 Access in order of insertion

The default accessOrder of LinkedHashMap is false, which provides access according to the insertion order, and does not override the put method of the parent class HashMap. But in HashMap, put is the Node node of HashMap. The Entry of LinkedHashMap is different from its structure, and how is it established What about a doubly linked list? Let's take a look at LinkedHashMap to insert related code.

Ignore the unrewritten put => putValue code part, we directly observe the rewritten

newNode

  • HashMap
  • LinkedHashMap rewrite

    Control the addition of new nodes to the end of the linked list, so that every time new nodes are added to the end, you can ensure the insertion order.
    Continue to study linkNodeLast

linkNodeLast

Add a node and append it to the end of the linked list.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// link at the end of list

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {

    LinkedHashMap.Entry<K,V> last = tail;

    // 新增于尾节点

    tail = p;

    // last 为null,说明链表为空

    if (last == null)

        head = p;

    // 链表非空,建立新节点和上一个尾节点的前后关系

    else {

        // 将新节点 p 直接接在链尾

        p.before = last;

        last.after = p;

    }

}

It can be seen that by adding the head and tail nodes, the before and after attributes of the node on the basis of HashMap, the node can be added directly to the tail node every time it is added, and the maintenance in accordance with the insertion order can be achieved The purpose of the linked list structure!

  • Steps to create a linked list

    of graphs The blue part is the method of HashMap The
    orange part is the unique method of LinkedHashMap

Note that although LinkedHashMap is also a doubly linked list, it only provides one-way access from the beginning to the end in the order of insertion, and it is not as accessible as LinkedList.

  • LinkedHashMap is accessed through an iterator, and the default is to start from the head node. During the

    iteration process, continually visit the after node to complete the traversal.

    1 place to check
    2 places through the node after attribute to find the successor node

5 Deletion of linked list nodes

  • The callback stored in HashMap that allows LinkedHashMap post-processing is the

    same as the insert operation. The code related to the LinkedHashMap delete operation is also directly implemented by the parent class. When deleting the node, the parent class will not repair the LinkedHashMap doubly linked list. So after deleting and nodes, how can the deleted nodes be safely removed from the double linked list? In fact, after deleting the node, the callback method afterNodeRemoval will be called. LinkedHashMap rewrites this method.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// e 为已经删除的节点

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

    LinkedHashMap.Entry<K,V> p =

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

    // 将 p 节点的前驱后后继引用置 null,辅助 GC

    p.before = p.after = null;

    // p.before 为 null,表明 p 是头节点

    if (b == null)

        head = a;

    else

        // 否则将 p 的前驱节点连接到 p 的后继节点

        b.after = a;

    // a 为 null,表明 p 是尾节点

    if (a == null)

        tail = b;

    else

        // 否则将 a 的前驱节点连接到 b

        a.before = b;

}

The main process of deleting elements:

  1. Position the bucket according to the hash
  2. Traverse the linked list or call the delete method related to the red-black tree
  3. Remove to remove from the doubly-linked list of nodes LinkedHashMap maintenance
    5088755_1583897219283_48356470140921DD4FA1E2C40982DE97uploading.4e448015.gifdump failed to re-upload canceled

6 LRU (Least recently used, least recently used)

3.2.1 Chestnuts

Frequently accessed elements will be appended to the end of the queue, so the infrequently accessed data is naturally close to the head of the team, and then you can set a deletion strategy, such as when the number of Map elements is greater than what, delete the head node

3.2.2 Elements were moved to the end of the team

When get, the element will be moved to the end of the line:

1

2

3

4

5

6

7

8

9

10

11

public V get(Object key) {

    Node<K,V> e;

    // 调用 HashMap  get 方法

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

        return null;

    // 如果设置了 LRU 策略

    if (accessOrder)

    // 这个方法把当前 key 移动到队尾

        afterNodeAccess(e);

    return e.value;

}

From the above source code, we can see that the current access node is moved to the end of the queue through the afterNodeAccess method, which is not just the get method. The frequently visited nodes move to the end of the team, so the nodes near the head of the team are naturally the elements that are rarely visited.

436 original articles have been published · 1313 praises · 630,000 views

Guess you like

Origin blog.csdn.net/qq_33589510/article/details/105459764