4.LinkedHashMap = HashMap + 双向链表
- before after构成双向链表
static class Entry extends HashMap.Node {
Entry before, after;
Entry(int hash, K key, V value, Node next) {
super(hash, key, value, next);
}
}
- 关于put(key, value)
step1.调用HashMap.put
step2.调用HashMap.putVal
step3.putVal中调用LinkedHashMap.newNode(hash, key, value, null);
调用linkNodeLast将该结点加入到双向链表的末尾。
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
Node newNode(int hash, K key, V value, Node e) {
LinkedHashMap.Entry p =
new LinkedHashMap.Entry(hash, key, value, e);
linkNodeLast(p);
return p;
}
private void linkNodeLast(LinkedHashMap.Entry p) {
LinkedHashMap.Entry last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
- 关于get(key)
accessOrder——true表示access-order,false表示insertion-order
accessOrder为true就会将最近访问的结点放到链表末尾。
public V get(Object key) {
Node e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
- 实现LRU
这里的LRU将最老的放在链表头,最近刚访问过的放在链表尾,如果需要删除,就删除链表头。
只需要重写其removeEldestEntry()
HashMap.putVal方法中最后调用afterNodeInsertion
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
...
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
LinkedHashMap实现了afterNodeInsertion,该方法调用了removeEldestEntry,若removeEldestEntry条件满足,就会删除head。
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}