LinkedHashMap 源码简单分析

日常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;

猜你喜欢

转载自blog.csdn.net/Android_LeeJiaLun/article/details/108326071