LinkedHashMap继承了HashMap,实现了Map接口。
它在HashMap的基础上为将每个插入节点添加了before和after两个指针,记录节点插入顺序,构成一个双向链表。

1. 源码分析

1.1. 构造方法

image.png

一共有五种构造方法,其中前四种默认accessOrder为false,然后直接调用HashMap的对应构造方法;第五种构造方法可以指定accessOrder为true/false。

  1. public LinkedHashMap() {
  2. super();
  3. accessOrder = false;
  4. }

1.2. newNode()

LinkedHashMap重写了HashMap中的newNode()方法,创建出一个LinkedHashMap.Entry对象,在Node的基础上增加了beforeafter个指针,形成双向链表(全局插入顺序双向)。
(prev和next这两个指针形成bucket内的双向链表)

  1. Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
  2. LinkedHashMap.Entry<K,V> p =
  3. new LinkedHashMap.Entry<K,V>(hash, key, value, e);
  4. //将这个节点置于全局双向链表的尾部
  5. linkNodeLast(p);
  6. return p;
  7. }

1.3. afterNodeInsertion()

LinkedHashMap重写了HashMap中的afterNodeInsertion(boolean evict)方法。
evict:vt.逐出,驱逐
这个方法在LinkedHashMap中不起作用,因为removeEldestEntry方法始终返回false,但自定义类继承LinkedHashMap并重写该方法可以在指定条件下删除链表头部的旧节点。

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);
    }
}

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    return false;
}


1.4. afterNodeAccess()

LinkedHashMap重写了HashMap中的get(Object key)、getOrDefault()方法。
增加了一次对accessOrder的判断,如果accessOrder为true,则会调用afterNodeAccess方法,将访问点移动到链表的末尾。

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;
}

/**
     * {@inheritDoc}
     */
public V getOrDefault(Object key, V defaultValue) {
    Node<K,V> e;
    if ((e = getNode(hash(key), key)) == null)
        return defaultValue;
    if (accessOrder)
        afterNodeAccess(e);
    return e.value;
}