美文网首页
Java源码分析-LinkedHashMap

Java源码分析-LinkedHashMap

作者: gatsby_dhn | 来源:发表于2016-10-09 00:32 被阅读191次

    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的快速访问,同时也按访问顺序或插入顺序维护了双向链表。

    相关文章

      网友评论

          本文标题:Java源码分析-LinkedHashMap

          本文链接:https://www.haomeiwen.com/subject/lmlpyttx.html