写在前面的话:本文是基于读者已经了解了一部分HashMap源码的基础上写的,如果还没有看过HashMap的源码,可以点击链接跳转:HashMap详解,拿过来吧你(部分)
1、LinkedHashMap介绍
这个类是HashMap的子类,只不过在原有的Node类之上,增加了两个指针域before和after,before用于指向这个节点最近之前添加的节点,after将指向其之后再添加的节点,由于大部分内容继承于HashMap,所以它也是线程不安全的。
它不仅解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题,而且LinkedHashMap 对访问顺序也提供了相关支持。在一些场景下,该特性很有用,比如缓存。
2、属性
private static final long serialVersionUID = 3801124242820219131L;
transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;
final boolean accessOrder;
3、构造器
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
4、节点类
是继承于HashMap.Node类的,之所以要继承重写这个类,主要是为了既能增加两个指针域,而且不需要编写重复代码;而且重写这个类,方便后续的newNode方法的重写。
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);
}
}
5、put方法
LinkedHashMap中没有重写put方法,功能性代码几乎完全继承了HashMap类,但是重写了newNode方法;
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 = this.tail;
this.tail = p;
if (last == null)
this.head = p;
else {
p.before = last;
last.after = p;
}
}
6、关于几个后置方法
afterNodeInsertion(putVal中被调用)、afterNodeAccess(putVal、get中被调用)、afterNodeRemoval(removeNode中被调用)分别是在节点进行增删查,即在putVal、get、removeNode方法中回调执行执行;这三个方法都是重写了父类HashMap中的,只不过在HashMap中,这几个方法都为空方法,这三个方法设计的目的,就是为了支持LinkedHashMap.
用于增加节点后回调的方法:
根据需要把头节点删除。
void afterNodeInsertion(boolean evict) {
LinkedHashMap.Entry<K,V> first;
if (evict && (first = this.head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
用于删除节点后回调的方法:
就是在双向链表中,把被删除的节点去掉。
void afterNodeRemoval(Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
this.head = a;
else
b.after = a;
if (a == null)
this.tail = b;
else
a.before = b;
}
用于查询节点后回调的方法:
如果指定这个LinkedHashMap是按照访问进行排序的话,那么访问后的排序工作在这里完成,即将被访问的节点移动到链表的末尾。
void afterNodeAccess(Node<K,V> e) {
LinkedHashMap.Entry<K,V> last;
if (this.accessOrder && (last = this.tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e,
b = p.before,
a = p.after;
p.after = null;
if (b == null)
this.head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
this.head = p;
else {
p.before = last;
last.after = p;
}
this.tail = p;
++modCount;
}
}
|