美文网首页
LinkedHashMap 源码简单分析

LinkedHashMap 源码简单分析

作者: 嘉伦哥 | 来源:发表于2020-04-16 20:23 被阅读0次

    日常Android 应用开发中,使用的LinkedHashMap的场景还是比较常见的。比如:GlideLruChche、做一些有序的存储(访问顺序或者插入顺序)的队列。那么今天就简单剖析一下LinkedHashMap 的源码,看看它 作为继承HashMap后 有什么特别之处。

    构造方法

    1586923559(1).jpg

    可以看到,构造方法很多,先看看空参构造:

    /**
         * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
         * with the default initial capacity (16) and load factor (0.75).
         */
    
        public LinkedHashMap() {
            super();
            accessOrder = false;
        }
    

    注释:构造一个以插入顺序的LinkedHashMap,初始的容量为16,加载因子为0.75(HashMap也为0.75,至于为什么,就比较复杂了 - -!)
    决定顺序类型的是构造中的 accessOrder字段,false:插入顺序true:访问顺序,也就是说,在常用的场景下,如果使用无参构造new出来的LinkedHashMap,默认是基于插入顺序的(有序)。那么它是如何保证有序的呢?

        /**
         * HashMap.Node subclass for normal LinkedHashMap entries.
         */
        static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
            LinkedHashMapEntry<K,V> before, after;
            LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
                super(hash, key, value, next);
            }
        }
    

    我们看到,LinkedHashMap 定义了一个继承了HashMap.Node的静态内部类,而Node类是HashMap的底层数据结构,实现了数组+链表/红黑树的结构,而LinkedHashMapEntry类保留了HashMap的数据结构,同时通过before,after实现了双向链表结构(HashMap中Node类只有next属性,并不具备双向链表结构)。那么before,after和next到底什么关系呢。

    核心方法

    • afterNodeAccess
     void afterNodeAccess(Node<K,V> e) { // move node to last
            LinkedHashMapEntry<K,V> last;
            if (accessOrder && (last = tail) != e) {
                LinkedHashMapEntry<K,V> p =
                    (LinkedHashMapEntry<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;
            }
        }
    

    当accessOrder 为true并且访问节点不等于尾节点时,该方法才有意义,通过before、after重定向,将新访问节点链接为链表尾节点。

    • afterNodeInsertion()
     void afterNodeInsertion(boolean evict) { // possibly remove eldest
            LinkedHashMapEntry<K,V> first;
            if (evict && (first = head) != null && removeEldestEntry(first)) {
                K key = first.key;
                removeNode(hash(key), key, null, false, true);
            }
        }
    

    从代码得知,只有removeEldestEntry(first) 为true 时,方法才意义,却永远return false,所以需要重写

    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
            return false;
        }
    
    

    如果使用LinkedHashMap实现一个简单的LRUCache。那么就应该重写removeEldestEntry(),当超出缓存容器大小时移除最老的首节点,当然 在初始化LinkedHashMap 时,要将accessOrder设置为true;

    相关文章

      网友评论

          本文标题:LinkedHashMap 源码简单分析

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