finalize() 方法已被彻底移除,不应用于资源清理;应使用 try-with-resources 或 Cleaner 替代,确保资源确定性释放与安全异步清理。

Java 中的 finalize() 方法早已被弃用,**不应用于资源清理或关键逻辑**。它既不可靠、不可预测,也无法保证执行时机,甚至可能拖慢垃圾回收(GC)过程。自 Java 9 起被标记为 @Deprecated,Java 14 开始默认禁用,Java 18 彻底移除(JEP 421)。理解它有助于避开陷阱,但真正该掌握的是现代替代方案。
finalize() 为什么不可靠
该方法由 JVM 在对象被 GC 回收前“尝试”调用,但存在严重问题:
- 执行时间不确定:可能永远不被调用(如程序退出前 GC 未触发)
- 仅调用一次:即使对象在 finalize 中“自救”(如将 this 赋给静态引用),再次变为可回收时也不会重调
- 性能开销大:启用 finalize 的对象会被放入特殊队列,延长生命周期并增加 GC 压力
- 无异常传播:finalize 中抛出的异常会被静默吞掉,且不会中断回收流程
资源清理的正确方式:try-with-resources
对于实现了 AutoCloseable 接口的资源(如文件、网络连接、数据库连接),应优先使用 try-with-resources 语句,在作用域结束时自动、确定地释放:
try (FileInputStream fis = new FileInputStream("data.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
String line = reader.readLine();
// 使用资源
} // 自动调用 fis.close() 和 reader.close()
这是编译器级别的保障,无需依赖 GC 或 finalize,安全、简洁、可预测。
立即学习“Java免费学习笔记(深入)”;
需要延迟清理的场景:Cleaner(推荐替代 finalize)
当确实需要在对象不可达后执行非关键清理(如释放本地内存、注销监听器),应使用 java.lang.ref.Cleaner —— 它基于虚引用(PhantomReference),不阻止 GC,也不影响对象生命周期:
- Cleaner 是线程安全的,可复用
- 清理动作在独立线程中异步执行,不阻塞 GC
- 比 finalize 更可控、更轻量
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
public MyClass(ByteBuffer directBuffer) {
this.directBuffer = directBuffer;
this.cleanable = cleaner.register(this,
() -> directBuffer.clear()); // 清理逻辑
}
避免 finalize 的实践建议
直接删除所有 finalize() 方法定义。若代码中已有,按以下顺序重构:
- 检查是否在清理资源 → 改用 try-with-resources 或显式 close()
- 是否在记录日志或调试 → 改为构造/销毁时手动打点,或用 JFR(Java Flight Recorder)监控
- 是否依赖“对象销毁时通知” → 改用 Cleaner,或通过业务层主动管理生命周期(如池化对象的 returnToPool())
- 第三方库使用了 finalize?升级到新版本,或查阅其文档确认替代 API
不复杂但容易忽略:finalize 不是“析构函数”,也不是兜底机制。真正的健壮性来自明确的资源生命周期管理和现代引用工具的合理使用。


















