Java源码分析-LinkedHashMap

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

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

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


Java源码分析-LinkedHashMap_第1张图片
图片来自网络.jpg

继承关系

public class LinkedHashMap
    extends HashMap
    implements Map

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

内部节点

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

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

成员变量

    transient LinkedHashMap.Entry head;   //链表头结点

    /**
     * The tail (youngest) of the doubly linked list.
     */
    transient LinkedHashMap.Entry 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 eldest() {
    LinkedEntry 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 e = entryForNullKey;
        if (e == null)
            return null;
        if (accessOrder)
            makeTail((LinkedEntry) e);
        return e.value;
    }

    int hash = Collections.secondaryHash(key);
    HashMapEntry[] tab = table;
    for (HashMapEntry 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) e);    //将当前节点放到链表尾部
            return e.value;   //返回节点的值
        }
    }
    return null;
}

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

Java源码分析-LinkedHashMap_第2张图片
图片来自网络.jpg

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

总结

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

你可能感兴趣的:(Java源码分析-LinkedHashMap)