LinkedHashMap源码阅读(1.8)

224 阅读2分钟

总览

开局一张图 image.png LinkedHashMap源码整体结构 image.png

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

LinkedHashMap继承了HashMap,那不同点在哪里呢?

新增变量

  • final boolean accessOrder;
  • transient LinkedHashMap.Entry<K,V> tail;
  • transient LinkedHashMap.Entry<K,V> head; 从名字上可以看出head,tail是双向链表的头尾节点,那accessOrder的作用呢?
    /**
     * The iteration ordering method for this linked hash map: <tt>true</tt>
     * for access-order, <tt>false</tt> for insertion-order.
     * 翻译过来就是这个值影响迭代顺序,true迭代顺序是访问顺序,false迭代顺序是插入顺序
     * @serial
     */
    final boolean accessOrder;

新增内部类

  • static class Entry<K,V> extends HashMap.Node<K,V>
  • final class LinkedKeySet extends AbstractSet
  • final class LinkedValues extends AbstractCollection
  • final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>>
  • abstract class LinkedHashIterator
  • final class LinkedKeyIterator extends LinkedHashIterator implements Iterator
  • final class LinkedValueIterator extends LinkedHashIterator implements Iterator
  • final class LinkedEntryIterator extends LinkedHashIterator implements Iterator<Map.Entry<K,V>>

细节

accessOrder变量影响

    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;
   }
   //把当前访问节点放到链表尾
    void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMap.Entry<K,V> last;
        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;
        }
    }

链表的构建

可以发现LinkHashMap 并没有重写put方法,那双链表是怎么构建的呢?

    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;
    }
    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
        //关键代码
        linkNodeLast(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的着3个方法么?

    // Callbacks to allow LinkedHashMap post-actions
    void afterNodeAccess(Node<K,V> p) { }
    void afterNodeInsertion(boolean evict) { }
    void afterNodeRemoval(Node<K,V> p) { }
    //afterNodeAccess 前面已经贴出来了
    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);
        }
    }
    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;
    }