LinkedHashMap 在初始化的时候,有两种使用模式
- 插入顺序 ,遍历时,按照put顺序输出
- 访问顺序,这种情况下是否会扩容 ????
- 当处于访问顺序模式的时候,什么情况下会删除eldest 元素。
HashMap 是无序的 。那么LinkedHashMap 是如何保持有序的
- HashMap 以拉链法处理冲突, 数组下标对应的是 元素的hash 值 对数组长度的求余。
- LinkedHashMap 使用双向链表来,保持顺序和方便操作
LinkedHashMap 是HashMap 的子类 ,它是如何在不侵入 HashMap的 前提下 实现双向链表的功能
- put 一个新的元素的 时候,会触发 Node 的创建, LinkedHashMap 重写了创建的过程,在Node创建的时候建立和维护双向链表
双向链表的维护操作 : put(Key不存在) ,put (Key存在),删除
- 最简单的删除操作, HashMap 在删除一个 Node 也就是 Entry 后会调用 afterNodeRemoval 方法 。LinkedHashMap 覆写了这个方法,由于是双向链表,所以删除操作很快。
- put(Key不存在) 会 调用 afterNodeInsertion(boolean evict) 。这个方法是干嘛的呢? 当evict 为True 的时候,且 处于LRU 模式,会触发维护访问次序的方法。
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
上面的 移除逻辑需要满足 removeEldestEntry(first) 为 true 。
默认情况下 ,是不会移除EldestEntry 。
如要要实现LRU ,需要 手动移除,或者 继承 LinkedHashMap 并且 重写这个方法。
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
访问顺序的维护
先明确一点,在访问模式下:
- 最近访问的元素,是放在链表的尾部。
- 很久不使用的元素,放在链表的头部。
当我们调用get/getOrDefault/replace等方法时 会触发 afterNodeAccess 方法,把对应的Node 移动到双向链表的尾部
实现一个最简单的 LRUCache
leetcode 146题
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class LRUCache extends LinkedHashMap<Integer, Integer> {
int maxCapacity;
public LRUCache(int capacity) {
super(16,0.75f,true);
maxCapacity = capacity;
}
public int get(int key) {
return super.getOrDefault(key,-1);
}
public void put(int key, int value) {
super.put(key,value);
}
@Override
protected boolean removeEldestEntry(Entry eldest) {
return size()>maxCapacity;
}
}