1、什么是 finalize()
方法?
finalize()
方法是 Java 中 java.lang.Object
类提供的一个方法,是JVM回收该垃圾象内存之前调用的方法,其声明如下:
java
protected void finalize() throws Throwable
- 它是 Object 类的一个 protected受保护的方法,所有 Java 类都默认继承了这个方法。
-
finalize()
方法是在垃圾回收器(Garbage Collector, GC)准备回收某个对象所占用的内存之前,由 JVM 自动调用的。(垃圾回收之前自动调用) - 可以重写该方法,用于在对象被销毁前执行一些清理工作(如关闭资源、释放外部链接等)。
- 方法可以抛出 Throwable(包括 Exception 和 Error),但一般不建议抛出异常
- 默认的
Object.finalize()
是一个空实现,什么都不做
2、finalize()
的基本工作原理
当一个对象没有任何引用指向它(成为垃圾 ),垃圾回收器会在某个不确定的时间将其标记为可回收。
在真正回收该对象的内存之前,JVM 会调用该对象的 finalize()
方法(如果该对象重写了此方法)
执行顺序:
1、对象成为垃圾
2、垃圾回收器发现该对象可被回收
3、在回收该对象内存之前,JVM 会调用该对象的 finalize()
方法(如果存在)。
4、垃圾回收器在某个时间点真正回收该对象占用的内存。
⚠️ 注意:调用 finalize() 并不意味着对象一定会被回收! 甚至也有可能通过 finalize() 方法处理来"复活"对象(极为罕见且不推荐)。
**3、**重写 finalize()
方法(代码示例)
java
public class User{
private String name;
public User(String name) {
this.name = name;
System.out.println(name + " 对象已创建");
}
@Override
protected void finalize() throws Throwable {
try {
System.out.println(name + " 对象即将被垃圾回收,finalize() 被调用!");
// 可以在这里执行一些资源释放逻辑,但不保证一定会执行
} finally {
super.finalize(); // 调用父类的 finalize(一般无实际意义)
}
}
}
测试代码
java
public class Test {
public static void main(String[] args) {
new User("TestObject");
// 提醒 JVM 进行垃圾回收(但不保证马上执行!)
System.gc();
// 提醒 JVM 进行 finalize 线程的处理
System.runFinalization();
System.out.println("程序结束");
}
}
输出结果:
html
TestObject 对象已创建
TestObject 对象即将被垃圾回收,finalize() 被调用!
程序结束
注意:输出结果可能不保证顺序,也不保证 finalize 一定会被调用!
4、finalize()
的特点
-
调用时机不确定
finalize()
的调用是由 垃圾回收器控制的,无法控制它何时执行,甚至不保证一定会执行。- 即使调用了
System.gc()
或System.runFinalization()
,也只是建议 JVM 执行 GC,不保证效果。
-
不保证一定会被执行
- 如果 JVM 在对象成为垃圾后直接回收内存,而没有调用
finalize()
,那么该方法就不会被执行。 - 在程序退出时,某些未被回收的对象的
finalize()
也可能根本不会被调用。
- 如果 JVM 在对象成为垃圾后直接回收内存,而没有调用
-
性能开销大
- 使用
finalize()
会 增加垃圾回收的负担,JVM 需要额外维护一个 Finalizer 队列与线程来处理它。 - 导致 GC 变慢,对象回收延迟。
- 使用
-
不要依赖它释放关键资源
- 关闭文件、数据库连接、网络连接等,绝对不要依赖
finalize()
来释放资源,因为它可能永远不会被调用!
- 关闭文件、数据库连接、网络连接等,绝对不要依赖
5、做资源清理时推荐的方式
1. 使用 try-with-resources
(Java 7+ 以后)
代码示例:
java
try (FileInputStream fis = new FileInputStream("test.txt")) {
// 资源处理
} catch (IOException e) {
e.printStackTrace();
}
// fis 会自动调用 close(),无需 finalize!
2.手动在 finally 块中调用 close()
java
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
// 资源处理
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close(); // 关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
做资源清理时避免使用 finalize(),在 Java 9 开始,finalize() 方法已被标记为 @Deprecated(since="9"),表示不推荐使用,未来可能会被移除。Java 官方文档明确指出:不应依赖 finalize() 进行必要的清理工作。
6、补充:finalize()
的极端情况:对象"复活"
java
@Override
protected void finalize() throws Throwable {
System.out.println("finalize() 被调用,尝试复活对象");
SomeClass.saved = this; // 不要这样做!
}
在极少数情况下,在 finalize() 方法中将 this 赋值给某个静态变量,可能让对象"复活"(即暂时不被回收),但这种做法极其不推荐,会导致内存泄漏和不可预测的行为。