深入分析LinkedHashMap (JDK1.8)
类名和继承关系
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
内部存储结构
/** * HashMap.Node subclass for normal LinkedHashMap entries. */ 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); } } /** * 用于指向双向链表的头部 */ transient LinkedHashMap.Entry<K,V> head; /** * 用于指向双向链表的尾部 */ transient LinkedHashMap.Entry<K,V> tail;
LinkedHashMap
实际是在HashMap
的Node
结构里面加上双向链表在
LinkedHashMapMap
中,所有put
进来的Entry
都保存在HashMap
中,但由于它又额外定义了一个以head
为头结点的空的双向链表,因此对于每次put
进来Entry
还会将其插入到双向链表的尾部。由上图,除去红色双向箭头就是一个
HashMap
,只看红色双向箭头则是一个双向链表。所以,LinkedHashMap
就是一个标准的HashMap+LinkedList
。LinkedHashMap的构造方法
public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; }
比
HashMap
多了一个accessOrder
的参数,用来指定按照LRU
排列方式还是顺序插入的排序方式get()方法
public V get(Object key) { Node<K,V> e; //调用HashMap的getNode的方法 if ((e = getNode(hash(key), key)) == null) return null; //在取值后对参数accessOrder进行判断,如果为true,执行afterNodeAccess if (accessOrder) afterNodeAccess(e); return e.value; }
accessOrder为true则表示按照基于访问的顺序来排列
//将最近使用的Node,放在链表的最末尾 void afterNodeAccess(Node<K,V> e) { // move node to last LinkedHashMap.Entry<K,V> last; //仅当按照LRU原则且e不在最末尾,才执行修改链表,将e移到链表最末尾的操作 if (accessOrder && (last = tail) != e) { //将e赋值临时节点p, b是e的前一个节点, a是e的后一个节点 LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<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; } }
put()方法
LinkedHashMap
没有重写put
方法,调用的都是HashMap
的put
方法。为什么它也会执行afterNodeAccess()
方法呢,因为这个方法HashMap
就是存在的,但是没有实现,LinkedHashMap
重写了afterNodeAccess()
这个方法。