Skip to content

Java里有哪四种引用类型?有什么区别?虚引用主要是干什么的?

Java 四种引用类型概述

  • 定义
  • Java 提供了四种引用类型(Reference Types)来控制对象与垃圾回收器(GC)的交互,分别是 强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和 虚引用(Phantom Reference)。这些引用类型决定了对象在垃圾回收时的存活行为。
  • 软引用、弱引用和虚引用定义在 java.lang.ref 包中,强引用是默认的引用方式。
  • 目的
  • 提供灵活的内存管理,优化资源使用,适用于缓存、资源清理等场景。

核心点

  • 四种引用类型的强度依次降低(强 > 软 > 弱 > 虚),影响对象被 GC 回收的时机;虚引用主要用于对象回收后的清理工作。

1. 四种引用类型及区别

以下详细说明每种引用类型的定义、行为、用途及区别:

(1) 强引用(Strong Reference)

  • 定义
  • 最常见的引用类型,对象通过普通变量引用创建。
  • 只要强引用存在,对象就不会被 GC 回收,即使内存不足(会导致 OOM)。
  • 语法
Object obj = new Object(); // 强引用
  • 行为
  • GC 不会回收强引用指向的对象,除非引用置为 null 或超出作用域。
  • 用途
  • 核心业务对象、必须保留的数据(如用户会话、数据库连接)。
  • 示例
String str = new String("Hello");
str = null; // 断开强引用,对象可被回收
  • 特点
  • 强度最高,优先级高于其他引用类型。
  • 可能导致内存泄漏,需显式管理。

(2) 软引用(Soft Reference)

  • 定义
  • 使用 SoftReference 类创建,对象在内存不足时可能被 GC 回收。
  • 语法
SoftReference<String> softRef = new SoftReference<>(new String("Hello"));
  • 行为
  • GC 在内存充足时保留软引用对象。
  • 内存不足(接近 OOM)时,GC 回收软引用对象(通常在年轻代 GC 或 Full GC 时)。
  • 用途
  • 缓存实现:如图片缓存、Web 页面缓存,内存不足时可释放。
  • 示例
SoftReference<String> softRef = new SoftReference<>(new String("Hello"));
String str = softRef.get(); // 获取对象
if (str == null) {
    // 对象被回收,重新创建
}
  • 特点
  • 适合非关键数据,内存敏感场景。
  • 回收时机依赖 JVM 实现(通常延迟回收)。

(3) 弱引用(Weak Reference)

  • 定义
  • 使用 WeakReference 类创建,对象在下一次 GC 时通常被回收(无论内存是否充足)。
  • 语法
WeakReference<String> weakRef = new WeakReference<>(new String("Hello"));
  • 行为
  • 只要 GC 运行(Minor GC 或 Full GC),弱引用对象几乎总是被回收。
  • 可与 ReferenceQueue 结合,监控对象回收。
  • 用途
  • 临时缓存:如 WeakHashMap,避免内存泄漏。
  • 事件监听器:防止对象因监听器引用无法回收。
  • 示例
WeakReference<String> weakRef = new WeakReference<>(new String("Hello"));
String str = weakRef.get();
System.gc(); // 触发 GC
if (weakRef.get() == null) {
    // 对象已被回收
}
  • 特点
  • 强度低于软引用,回收更激进。
  • 适合短期存活或可重建的对象。

(4) 虚引用(Phantom Reference)

  • 定义
  • 使用 PhantomReference 类创建,对象随时可能被 GC 回收,且无法通过虚引用访问对象。
  • 必须与 ReferenceQueue 结合使用,监控对象回收事件。
  • 语法
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);
  • 行为
  • 虚引用不影响对象生命周期,对象可随时回收。
  • 当对象被回收时,虚引用被加入关联的 ReferenceQueue,可执行清理逻辑。
  • 用途
  • 对象回收后清理:如释放非堆资源(文件句柄、socket)。
  • 调试和监控:跟踪对象回收时机。
  • 示例
ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue);
obj = null; // 断开强引用
System.gc(); // 触发 GC
Reference<?> ref = queue.poll();
if (ref != null) {
    // 对象被回收,执行清理
    System.out.println("Object reclaimed");
}
  • 特点
  • 强度最低,无法通过 get() 访问对象。
  • 专门为回收后处理设计,非直接引用。

2. 虚引用的主要作用

  • 主要作用
  • 虚引用用于在对象被垃圾回收后执行清理或通知操作,通常与 ReferenceQueue 配合,处理资源释放或日志记录。
  • 具体场景
  • 资源清理
    • 管理非 JVM 管理的资源(如本地文件、数据库连接)。
    • 示例:关闭文件句柄,防止资源泄漏。
  • 对象回收监控
    • 调试或性能分析,记录对象回收时间。
    • 示例:分析大对象(如缓存池)的生命周期。
  • 替代 finalize
    • Object.finalize() 已废弃(效率低、不确定性高),虚引用提供更可靠的回收后处理。
  • 实现机制
  • 虚引用对象被回收时,JVM 将其加入 ReferenceQueue
  • 应用程序通过 queue.poll()queue.remove() 获取通知,执行自定义逻辑。
  • 优势
  • 不影响 GC 决策,性能开销低。
  • 明确控制清理时机,避免 finalize 的不确定性。
  • 局限
  • 无法直接访问对象,功能单一。
  • 需手动轮询 ReferenceQueue,增加代码复杂度。

3. 四种引用类型对比

引用类型 强度 回收时机 是否可访问 典型用途 与 ReferenceQueue
强引用 最高 不回收(除非断开) 核心业务对象 无需
软引用 中高 内存不足时 是(get() 缓存 可选
弱引用 中低 下次 GC 是(get() 临时缓存 可选
虚引用 最低 随时回收 回收后清理 必须

4. 使用场景

  • 强引用
  • 数据库连接池、Web 会话对象。
  • 软引用
  • 图片缓存(如 Android Bitmap 缓存)。
  • Spring Boot 的配置缓存。
  • 弱引用
  • WeakHashMap 存储临时键值对。
  • 事件监听器,防止内存泄漏。
  • 虚引用
  • 数据库连接关闭时的资源清理。
  • 调试大对象回收(如 GC 日志分析)。

5. 面试角度

  • 问“四种引用”
  • 提强、软、弱、虚,说明强度和回收时机。
  • 问“区别”
  • 提表格对比,重点回收时机和用途。
  • 问“虚引用作用”
  • 提回收后清理、替代 finalize,结合 ReferenceQueue
  • 问“场景”
  • 提缓存(软/弱)、资源清理(虚)、业务对象(强)。

6. 总结

Java 的四种引用类型是强引用、软引用、弱引用和虚引用,强度依次降低,分别适用于不同内存管理场景。强引用防止回收,软引用用于内存敏感缓存,弱引用适合临时数据,虚引用专门处理对象回收后的清理工作(通过 ReferenceQueue 实现)。虚引用无法访问对象,主要用于资源释放和回收监控,替代不可靠的 finalize。面试可提对比表格、代码示例或虚引用场景,清晰展示理解。


如果您想深入某部分(如虚引用源码或 WeakHashMap 实现),请告诉我,我可以进一步优化!