Java源码分析-LinkedHashMap

2016-10-09  本文已影响191人  gatsby_dhn

LinkedHashMap继承自HashMap,同时也维护了元素的插入顺序。内部多了一个双向循环链表的维护,该链表是有序的,可以按元素插入顺序或元素最近访问顺序(LRU)排列。来看下源码吧。

支持原创,转载请注明出处。

LinkedHashMap是一个维护了一个双向链表的HashMap:


图片来自网络.jpg

继承关系

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

LinkedHashMap继承自HashMap,最好先看下HashMap的源码

内部节点

    static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

Entry继承自HashMap.Node,同时增加了指向前一个和后一个节点的引用。

成员变量

    transient LinkedHashMap.Entry<K,V> head;   //链表头结点

    /**
     * The tail (youngest) of the doubly linked list.
     */
    transient LinkedHashMap.Entry<K,V> tail;  //链表尾节点
 
    final boolean accessOrder;                 //是否开启最近最久未使用算法

构造函数

    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

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

主要的工作是设置accessOrder这个成员变量,其他的交给父类构造函数。

核心方法

eldest方法

public Entry<K, V> eldest() {
    LinkedEntry<K, V> eldest = header.nxt;
    return eldest != header ? eldest : null;
}

该方法返回的就是链表头部的节点。头结点代表最久未访问的节点。
看下get方法:

@Override public V get(Object key) {
    /*
     * This method is overridden to eliminate the need for a polymorphic
     * invocation in superclass at the expense of code duplication.
     */
    if (key == null) {
        HashMapEntry<K, V> e = entryForNullKey;
        if (e == null)
            return null;
        if (accessOrder)
            makeTail((LinkedEntry<K, V>) e);
        return e.value;
    }

    int hash = Collections.secondaryHash(key);
    HashMapEntry<K, V>[] tab = table;
    for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];   
            e != null; e = e.next) {       //遍历链表
        K eKey = e.key;
        if (eKey == key || (e.hash == hash && key.equals(eKey))) {  //若找到
            if (accessOrder)
                makeTail((LinkedEntry<K, V>) e);    //将当前节点放到链表尾部
            return e.value;   //返回节点的值
        }
    }
    return null;
}

该方法先计算Hash值,然后根据Hash值确定桶,遍历桶中的节点,若找到,则返回该节点的值,并将该节点放到链表的末尾。所以头结点就是最久为访问的节点。
看张图就清楚了:

图片来自网络.jpg

这张图中,我们先删除了节点3,然后插入了节点6,接着访问节点4,访问时会先删除节点4,并将节点4放入链表的末尾。

总结

LinkedHashMap实现了HashMap的快速访问,同时也按访问顺序或插入顺序维护了双向链表。

上一篇下一篇

猜你喜欢

热点阅读