LinkedHashMap
- 组合模式,将
Entry
聚合到内部
- 实现上与
HashMap
基本一致
- 新增一个链表的结构,按照操作顺序连接,LRU结构
- 实现了几个方法,在HashMap是空实现
Entry
- 继承
HashMap.Node
,多了before/after
维护顺序
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);
}
}
newNode
- 创建
Node
的方式与HashMap
不同
newNode
,实际创建Node
,返回的是Entry
对象
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
}
}
put
public V put(K key, V value) {
//传入哈希 false代表是否覆盖原值,IfAbsent
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab
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)
else {
Node<K,V> e
if (p.hash == hash && //第一个就命中
((k = p.key) == key || (key != null && key.equals(k))))
e = p
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value)
else {
for (int binCount = 0
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null)
if (binCount >= TREEIFY_THRESHOLD - 1) // 大于等于7个
treeifyBin(tab, hash)
break
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break
p = e
}
}
if (e != null) { // 存在一个相同的key
V oldValue = e.value
if (!onlyIfAbsent || oldValue == null)
e.value = value
//hashMap进行空实现,LinkedHashMap实现了
afterNodeAccess(e)
return oldValue
}
}
++modCount
if (++size > threshold) //扩容
resize()
//hashMap进行空实现,LinkedHashMap实现了
afterNodeInsertion(evict)
return null
}
afterNodeAccess
LinkedHashMap<Integer, Integer> lhm = new LinkedHashMap<>(10, (float) (10 * 0.75), true);
void afterNodeAccess(Node<K,V> e) {
LinkedHashMap.Entry<K,V> last
//accessOrder 默认为false,true,且当前节点不是tail
if (accessOrder && (last = tail) != e) {
//强转
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after
p.after = null
//ab连接
if (b == null) //没有前节点,那么当前节点为head
head = a
else
b.after = a
if (a != null)
a.before = b
else //没有后节点 更新last
last = b
if (last == null) //last为null,则当前没有节点,更新head
head = p
else { //连接p和前一个节点
p.before = last
last.after = p
}
tail = p
++modCount
}
}
afterNodeInsertion
void afterNodeInsertion(boolean evict) {
LinkedHashMap.Entry<K,V> first;
if (evict && (first = 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;
}
afterNodeRemoval
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
}
小结
LinkedHashMap
继承了HashMap
,对部分空实现,进行了实现,多维护了一个LRU链表
- 功能实现上与
HashMap
一致,只是在put/remove
的过程中需要对其中的LRU
链表进行维护(实际上LinkedHashMap是没有进行维护的)
afterNodeAccess
在更新节点时调用,将最新使用的节点放到最后,默认没有调用
afterNodeInsertion
添加后,都要移除最老的头节点,默认没有调用
afterNodeRemoval
删除时,需要处理这个节点的链表关系,有调用