日常Android 应用开发中,使用的LinkedHashMap的场景还是比较常见的。比如:Glide、LruChche、做一些有序的存储(访问顺序或者插入顺序)的队列。那么今天就简单剖析一下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;
网友评论