应按对象生命周期和内存敏感度选择引用类型:强引用用于必需稳定存在的对象;软引用适用于可失效缓存;弱引用防止内存泄漏;虚引用仅用于回收通知与资源清理。

选哪种引用,关键看你想让对象“活多久”、以及“谁说了算”。不是凭感觉写 SoftReference 或 WeakReference,而是根据对象在业务中的角色和内存敏感度来定。
强引用:默认就用它,除非你有明确理由换
日常开发中 90% 的对象都该用强引用。比如 Service 实例、DTO、数据库连接池里的 Connection —— 它们必须稳定存在,不能被 GC 随意回收。
- 只要变量还持有它(没设为 null,没出作用域),JVM 就不会动它
- 哪怕内存快爆了,JVM 宁愿抛 OutOfMemoryError 也不收它
- 不需要额外类、不用配队列,写法最简单:Object obj = new Object();
软引用:做缓存,但要接受“内存不够时失效”
适合那些“有用但不关键”的数据,比如图片、网页 HTML、计算结果缓存。它会尽量留着,只在真正撑不住时才放手。
- 回收时机由 JVM 内存压力触发,不是某次 GC 就一定收
- 务必配合判空使用:BufferedImage img = softRef.get(); if (img != null) { ... }
- 可选加 ReferenceQueue,用于清理过期缓存条目(比如从 HashMap 中移除已回收的键)
弱引用:防内存泄漏,尤其搭配生命周期不一致的组件
典型场景是长生命周期对象持有短生命周期对象,比如 Handler 持有 Activity、ThreadLocal 存储用户上下文、监听器注册。
- 只要发生 GC,不管内存够不够,都会回收所指对象
- 使用前必须判空,否则容易 NPE;get() 返回 null 是常态,不是异常
- ThreadLocal 内部用弱引用存 key,就是为了避免 Activity 被静态 ThreadLocal 拖住不放
虚引用:不为保对象,只为“对象没了我知道”
它不能 get() 到对象,唯一价值是配合 ReferenceQueue 做事后通知。适用于需要资源清理的场景,比如 DirectByteBuffer 底层堆外内存释放、文件句柄关闭。
- 构造时必须传 ReferenceQueue,否则等于白写:new PhantomReference(obj, queue)
- get() 永远返回 null,别试图取对象内容
- 只有当对象被 finalize 后且真正回收时,虚引用才会入队,这时你可以安全执行清理逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











