weakhashmap 适合存储临时对象,因其键使用弱引用,当键无其他强引用时,gc 后自动移除对应键值对;但 value 为强引用,需避免其反向强引用 key 导致内存泄漏。

WeakHashMap 适合存储临时对象,关键在于它对键(key)使用弱引用,当键不再被其他强引用持有时,对应的键值对会在下一次垃圾回收时自动被移除。
为什么 WeakHashMap 适合临时对象
WeakHashMap 的设计初衷就是缓存类场景:键是业务中自然存在的对象(比如某个用户实例、UI 组件等),你不想因为缓存的存在而阻止这些对象被回收。只要外部不再强引用该键,WeakHashMap 就不会阻碍其回收,避免内存泄漏。
- 值(value)仍是强引用,所以如果 value 又反过来强引用了 key(比如 value 是一个内部类持有 this),会导致 key 无法被回收 → 键值对永远残留
- WeakHashMap 不同步,多线程访问需额外加锁或用 Collections.synchronizedMap 包装
- 遍历时可能遇到 key 已被回收的情况,get() 返回 null,entrySet() 中的 Entry 可能 key==null
典型用法:缓存与对象生命周期绑定
例如缓存某个配置对象的计算结果,且该配置对象本身生命周期较短:
WeakHashMap<config string> cache = new WeakHashMap();
Config config = new Config("theme-dark");
cache.put(config, computeThemePath(config)); // 存入
// 后续 config 被置为 null 或超出作用域
config = null;
System.gc(); // 触发回收(仅用于演示)
// 此时 cache.get(config) 会返回 null,且该 entry 已从 map 中清理</config>
使用时要注意的关键细节
WeakHashMap 的行为依赖于 JVM 的垃圾回收时机,不是“立即删除”,而是“下次 GC 后清理”。因此不能依赖它做精确的生命周期控制。
- 不要用字符串字面量或 Integer 等常量池对象作 key —— 它们被强引用,永远不会被回收,WeakHashMap 失去意义
- 避免在 value 中保存对 key 的强引用,否则形成循环引用,key 无法释放
- 判断是否存在某 key,用 containsKey();但 get() 返回 null 并不一定表示不存在,也可能是 key 已被回收
- 遍历推荐用 keySet() + for-each,并在操作前检查 key 是否 still alive(如再调用一次 get() 看是否非 null)
替代方案对比(按场景选)
如果需要更精细的过期控制(比如定时失效、LRU 淘汰),WeakHashMap 不够用:
- Guava Cache:支持软/弱引用键值、最大容量、过期时间、移除监听
- Caffeine:高性能,支持 weakKeys()/weakValues(),同时兼顾时效与淘汰策略
- ConcurrentHashMap + 引用队列手动管理:灵活但开发成本高,一般不推荐
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











