LinkedHashMap源码分析

Posted Uncle_Bjorney

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinkedHashMap源码分析相关的知识,希望对你有一定的参考价值。

1. LinkedHashMap

LinkedHashMap继承自HashMap,通过覆盖HashMap的一些方法,而在其内部维护了一个双向链表

1)get(覆盖)、afterNodeAccess、afterNodeInsertion(覆盖)和removeEldestEntry的组合可实现LRU(Least Recently Used)算法:继承LinkedHashMap,accessOrder置为true且覆盖removeEldestEntry方法

2)覆盖newNode、newTreeNode和afterNodeRemoval:在添加和删除节点时对双向链表进行维护

3)覆盖replacementNode、replacementTreeNode:在扩容分割红黑树时对双向链表进行维护

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {

    static class Entry<K,V> extends HashMap.Node<K,V> { // HashMap.TreeNode继承此类
        Entry<K,V> before, after; // 节点前置和后置节点(TreeNode中为prev和next)
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

    transient LinkedHashMap.Entry<K,V> head; // 双向链表头节点
    transient LinkedHashMap.Entry<K,V> tail; // 双向链表尾节点
    // accessOrder置为true && 继承LinkedHashMap,覆盖removeEldestEntry方法:可实现LRU(Least Recently Used)算法
    final boolean accessOrder;
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

    ......

    public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

    // 覆盖(+ accessOrder判断)
    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null) // HashMap.getNode
            return null;
        if (accessOrder)
            afterNodeAccess(e); // 在访问e后,将e移至双向链表尾部
        return e.value;
    }

    // 覆盖(HashMap中为noop)
    void afterNodeAccess(Node<K,V> e) { // 在访问e后,将e移至双向链表尾部
        LinkedHashMap.Entry<K,V> last;
        if (accessOrder && (last = tail) != e) { // accessOrder && e不是双向链表尾节点
            LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null) // p.before == null(p为头结点)
                head = a;
            else // p.before != null
                b.after = a;
            if (a != null) // p.after != null
                a.before = b;
            else // p.after == null(p为尾节点???tail != e)
                last = b;
            if (last == null) // 会出现???在多线程环境下???
                head = p;
            else {
                p.before = last; // p.before = tail
                last.after = p; // tail.after = p
            }
            tail = p;
            ++modCount;
        }
    }

    // 覆盖(HashMap中为noop)
    void afterNodeInsertion(boolean evict) { // removeEldestEntry
        LinkedHashMap.Entry<K,V> first;
        // evit(为true,见HashMap.put方法)&& 双向链表不为空 && removeEldestEntry条件成立
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true); // 删除head节点
        }
    }

    // 覆盖(new HashMap.Node -> new LinkedHashMap.Entry、+ 链接p至双向链表尾部)
    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { // HashMap.putVal方法中
        LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);
        linkNodeLast(p); // 将p链接至双向链表尾部
        return p;
    }

    // 覆盖(+ 链接p至双向链表尾部)
    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) { // HashMap.TreeNode.putTreeVal方法中
        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
        linkNodeLast(p); // 将p链接至双向链表尾部
        return p;
    }

    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        if (last == null) // 双向链表为空
            head = p;
        else { // 双向链表不为空
            p.before = last;
            last.after = p;
        }
    }

    // 覆盖(HashMap中为noop)
    void afterNodeRemoval(Node<K,V> e) {
        LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        p.before = p.after = null;
        if (b == null) // p.before == null(p为头结点)
            head = a;
        else // p.before != null
            b.after = a;
        if (a == null) // p.after == null(p为尾节点)
            tail = b;
        else // p.after != null
            a.before = b;
    }

    // 覆盖(new HashMap.Node -> new LinkedHashMap.Entry、+ 转移before和after属性)
    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) { // HashMap.TreeNode.untreeify方法中
        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
        LinkedHashMap.Entry<K,V> t = new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
        transferLinks(q, t); // 将q中的before和after属性转移到t中(可能修改双向链表的头尾节点)
        return t;
    }

    // 覆盖(+ 转移before和after属性)
    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) { // HashMap.TreeNode.treeify方法中
        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
        TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
        transferLinks(q, t); // 将q中的before和after属性转移到t中(可能修改双向链表的头尾节点)
        return t;
    }

    private void transferLinks(LinkedHashMap.Entry<K,V> src, LinkedHashMap.Entry<K,V> dst) {
        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
        if (b == null) // src.before == null
            head = dst;
        else // source.beore != null
            b.after = dst;
        if (a == null)// src.after == null
            tail = dst;
        else// src.after != null
            a.before = dst;
    }

    ... ...

}

2. 迭代器

在LinkedHashMap中的双向链表中迭代(Entry.after属性)

// LinkedEntrySet(entrySet方法)迭代器
final class LinkedEntryIterator extends LinkedHashIterator implements Iterator<Map.Entry<K,V>> {
    public final Map.Entry<K,V> next() { return nextNode(); }
}

// LinkedKeySet(keySet方法)迭代器
final class LinkedKeyIterator extends LinkedHashIterator implements Iterator<K> {
    public final K next() { return nextNode().getKey(); }
}

// LinkedValues(values方法)迭代器
final class LinkedValueIterator extends LinkedHashIterator implements Iterator<V> {
    public final V next() { return nextNode().value; }
}

// 用LinkedHashMap.Entry的after属性进行迭代访问
abstract class LinkedHashIterator {
    LinkedHashMap.Entry<K,V> next; // 下次调用next方法时返回的元素
    LinkedHashMap.Entry<K,V> current; // 当前next方法返回的元素
    int expectedModCount;

    LinkedHashIterator() {
        next = head;
        expectedModCount = modCount;
        current = null;
    }

    public final boolean hasNext() {
        return next != null;
    }

    final LinkedHashMap.Entry<K,V> nextNode() {
        LinkedHashMap.Entry<K,V> e = next; // 记录next
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (e == null)
            throw new NoSuchElementException();
        current = e; // current = next
        next = e.after; // next = next.after
        return e; // current
    }

    public final void remove() {
        Node<K,V> p = current;
        if (p == null)
            throw new IllegalStateException();
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        current = null; // current置空
        K key = p.key;
        removeNode(hash(key), key, null, false, false); // HashMap.removeNode -> LinkedHashMap.afterNodeRemoval
        expectedModCount = modCount;
    }
}

以上是关于LinkedHashMap源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Java源码分析LinkedHashMap源码分析

Java源码分析LinkedHashMap源码分析

JDK1.8源码分析之LinkedHashMap

死磕 java集合之LinkedHashMap源码分析

JAVA集合LinkedHashMap及其源码分析

LinkedHashMap源码分析与LRU实现