只能用 linkedhashmap,因为其提供受保护的 removeeldestentry 钩子方法,在 put 后自动回调以决定是否淘汰最老条目;而 hashmap 无访问/插入顺序维护机制,也不支持该回调。

Java 的 HashMap 本身不支持 removeEldestEntry 方法,这个方法属于 LinkedHashMap —— 它是 HashMap 的子类,但额外维护了插入或访问顺序的双向链表。要实现带自动淘汰策略的缓存(如 LRU 缓存),必须用 LinkedHashMap 并重写 removeEldestEntry。
为什么只能用 LinkedHashMap?
removeEldestEntry 是 LinkedHashMap 提供的受保护钩子方法,在每次 put 或 putAll 后被调用,用于决定是否移除“最老”的条目。而普通 HashMap 没有访问/插入顺序概念,也没有该回调机制,因此无法直接实现基于顺序的淘汰逻辑。
如何重写 removeEldestEntry 实现容量限制缓存?
只需继承 LinkedHashMap,在构造时启用访问顺序(可选),并重写 removeEldestEntry 返回 true 当当前 size 超过预设容量:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 调用父类构造器时传入
true表示按 访问顺序(get 也会更新顺序,适合 LRU);传false表示按 插入顺序(适合 FIFO) -
removeEldestEntry接收的是即将成为“最老”的条目(即链表头节点),返回true即触发移除 - 注意:该方法只在
put时触发,putIfAbsent、compute等也可能触发,但replace不会触发淘汰
示例代码(LRU 缓存,最大容量 3):
class LRUCache<k v> extends LinkedHashMap<k v> {
private final int capacity;
public LRUCache(int capacity) {
// true → access-order;initialCapacity 和 loadFactor 可按需调整
super(16, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<k v> eldest) {
return size() > capacity; // 超过容量就淘汰最老的
}
}</k></k></k>
关键细节和常见陷阱
-
size()在removeEldestEntry中返回的是 本次 put 后的新大小,所以判断size() > capacity是安全的 - 如果希望支持线程安全,不能只靠
synchronized包裹操作——应使用Collections.synchronizedMap(new LRUCache(...)),或改用ConcurrentHashMap + 手动维护队列(因为LinkedHashMap非线程安全) - 该机制不处理过期时间(TTL),如需时效性,需额外封装或选用
Caffeine、Guava Cache等成熟缓存库 -
get触发顺序更新的前提是构造时第三个参数为true;否则即使访问也不会改变“最老”判定
替代方案:不依赖 removeEldestEntry 的轻量实现
若想完全控制淘汰逻辑,或需要更复杂策略(如按权重、读写频率),可手动维护一个 LinkedHashMap 并在 put 后显式检查和移除:
- 重写
put方法,插入后立即判断是否超限,超限则调用remove(entrySet().iterator().next().getKey()) - 比
removeEldestEntry更灵活,但失去内置 hook 的简洁性,且需小心并发与迭代器失效问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










