WeakHashMap 的键会被自动清理是因为其键被 WeakReference 包装,GC 发现无强引用时会回收键并移除对应 Entry;value 非弱引用,若 value 强引用 key 则导致内存泄漏。

WeakHashMap 的键为什么会被自动清理
因为 WeakHashMap 内部用的是 WeakReference 包装键,只要 JVM GC 发现这个键没有其他强引用,就会在下一次清理时把整个 Entry 干掉——不是“定期扫描”,而是依赖 GC 触发,所以它不保证实时性。
- 常见错误现象:
WeakHashMap.get(key)突然返回null,但你没调remove,也没清空 map;其实是 key 被 GC 了 - 使用场景:适合做内存敏感的缓存,比如缓存大对象(如图片、解析后的 XML)的中间结果,且这些 key 本身也是临时对象(如局部创建的
String或自定义 POJO) - 注意:value 不是弱引用!如果 value 持有对 key 的强引用(比如 value 是个内部类实例、或显式存了 key),会导致 key 无法被回收,整个 Entry 就卡住不释放
WeakHashMap 和 HashMap 在 put/get 行为上有什么区别
表层 API 完全一致,但底层行为差异极大:put 后 key 可能在任意 GC 后消失,get 返回 null 不代表没存过,只代表 key 已不可达。
- 参数差异:不需要额外配置,但要注意 key 类型——必须是可被 GC 的对象;
new Integer(123)行,Integer.valueOf(123)(小整数缓存池里)不行,因为缓存池持强引用 - 性能影响:GC 压力略增(多了弱引用队列处理),但比手动维护引用映射轻量;遍历
entrySet()时可能看到“中途消失”的 Entry,建议用迭代器边遍历边检查getKey() != null - 兼容性:JDK 1.2+ 都支持,无版本陷阱;但 Android 低版本(
WeakHashMap 用作缓存时,怎么避免“查不到就重建”的恶性循环
直接 map.get(key) == null ? computeAndPut(key) : map.get(key) 是错的——两次 get 中间 key 可能被回收,第二次又落空,导致重复计算。
- 正确做法:用局部变量暂存 value,再判断是否为空
Value v = map.get(key);<br>if (v == null) {<br> v = expensiveCompute(key);<br> map.put(key, v); // 注意:这里 key 还活着<br>} - 更安全的做法:如果 key 构造成本高(比如 new 一个对象作 key),建议复用 key 实例,或改用
SoftReference+ 自定义 Map(WeakHashMap不适合 key 本身也重的情况) - 容易踩的坑:把字符串字面量(
"abc")当 key——它们在常量池,永不回收,WeakHashMap失效;应改用new String("abc")或其他运行时构造对象
WeakHashMap 的 key 是 null 会怎样
会抛 NullPointerException,和 HashMap 一样,但很多人误以为“弱引用能容忍 null”,其实不能。
立即学习“Java免费学习笔记(深入)”;
- 错误示例:
map.put(null, "value")→ 直接崩溃,堆栈里能看到WeakHashMap.put报 NPE - 使用场景:如果你需要支持 null key,别硬套
WeakHashMap,要么预处理(如用Optional.ofNullable(key)包一层),要么换结构(如ConcurrentHashMap+ 显式 null-key 管理) - 兼容性提醒:所有 JDK 版本行为一致,没例外










