LinkedHashMap继承自HashMap,同时也维护了元素的插入顺序。内部多了一个双向循环链表的维护,该链表是有序的,可以按元素插入顺序或元素最近访问顺序(LRU)排列。来看下源码吧。
支持原创,转载请注明出处。
LinkedHashMap是一个维护了一个双向链表的HashMap:
继承关系
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值确定桶,遍历桶中的节点,若找到,则返回该节点的值,并将该节点放到链表的末尾。所以头结点就是最久为访问的节点。
看张图就清楚了:
这张图中,我们先删除了节点3,然后插入了节点6,接着访问节点4,访问时会先删除节点4,并将节点4放入链表的末尾。
总结
LinkedHashMap实现了HashMap的快速访问,同时也按访问顺序或插入顺序维护了双向链表。