LinkedHashMap
结构
public class LinkedHashMap<K,V> extends HashMap<K,V>
implements Map<K,V>
特点
- 通过维护双向链表,解决了 HashMap 不能保持遍历顺序和插入顺序一致的问题
- 很好的支持LRU算法,accessOrder
- 非线程安全
- 允许null值
成员变量
//双链表头结点
transient LinkedHashMap.Entry<K,V> head;
//双链表尾节点
transient LinkedHashMap.Entry<K,V> tail;
//是否基于访问排序,默认false
final boolean accessOrder;
内部类
Entry
LinkedHashMap中维护的节点
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);
}
}
LinkedHashIterator
LinkedHashMap中的迭代器
abstract class LinkedHashIterator {
//下一元素
LinkedHashMap.Entry<K,V> next;
//当前元素
LinkedHashMap.Entry<K,V> current;
//期望的结构修改次数
int expectedModCount;
LinkedHashIterator() {
//指向双向链表的头结点
next = head;
expectedModCount = modCount;
current = null;
}
public final boolean hasNext() {
return next != null;
}
final LinkedHashMap.Entry<K,V> nextNode() {
LinkedHashMap.Entry<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
//指向下一节点
next = e.after;
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
重要方法
put(K key, V value)
继承HashMap中的put方法,覆盖了其中创建链表节点的newNode()方法来实现保存插入顺序
//HashMap
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
return new Node<>(hash, key, value, next);
}
//LinkedHashMap
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
//将新节点链入双向链表
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
remove(Object key)
继承HashMap中的remove方法,在删除节点后调用afterNodeRemoval(node)方法,此方法在HashMap中为空,LinkedHashMap提供其实现来维护双向链表
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//解除节点链接
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
afterNodeAccess(Node<K,V> e)
当accessOrder为TRUE,提供LinkedHashMap按照访问顺序排列,在HashMap中的get、getOrDefault和putVal、replace、compute、computeIfAbsent、compute方法中被调用使用(如果键存在)
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
//如果accessOrder为true且当前节点不是尾节点
if (accessOrder && (last = tail) != 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;
}
}
afterNodeInsertion(Node<K,V> e)
提供LRU算法的实现,在HashMap中的putVal和computeIfAbsent、compute、merge方法中被调用使用(value改变)
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
//如果evict为true、首节点不为空,removeEldestEntry条件返回true才执行删除
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
//判断在什么条件下移除最近最少使用的节点,通过覆盖该方法可自定义实现LRU策略
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}