Java 提供了一个 finalize()
方法,允许在垃圾回收器将对象从内存中清除之前,对对象进行必要的清理工作。以下内容将对 finalize()
的调用时机、析构函数的目的以及 final
和 finalize
的区别进行深入解析。
finalize() 方法
finalize()
是 Java 的一个特殊方法,它属于所有类的“祖宗”——Object
类,也就是说每个 Java 类都默认继承了这个方法。它的核心作用是:在垃圾回收器回收对象之前进行清理操作。
finalize() 方法什么时候被调用?
-
调用时机:
当垃圾回收器发现某个对象已经没有任何引用时,它会对该对象调用finalize()
方法,进行必要的清理操作。 -
调用过程:
-
假设有一个对象
Dog
,它占用了一块堆内存。对象的引用用变量d
表示:Dog d = new Dog();
-
当我们将
d
赋值为null
时:d = null;
这意味着程序中已经没有任何地方可以访问到这个
Dog
对象,它变成了“无主对象”。 -
此时,垃圾回收器会将这个对象标记为“可回收”。在实际回收之前,垃圾回收器会自动调用对象的
finalize()
方法。
-
-
注意:垃圾回收器并不会立即回收对象,也就是说,赋值为
null
并不等于立刻触发finalize()
。垃圾回收的时间是由 JVM 决定的。
析构函数(finalization) 的目的
析构函数的主要目标是:在对象被销毁之前完成清理工作。这种清理可能包括:
- 释放资源:比如关闭文件流、数据库连接等。
- 释放内存:回收程序中动态分配的资源,减少内存泄漏的风险。
举例说明:垃圾回收的过程
让我们看看一个例子来感受 finalize()
的执行:
public class Dog {@Overrideprotected void finalize() throws Throwable {System.out.println("Dog对象即将被垃圾回收!");}
}public class Main {public static void main(String[] args) {Dog d = new Dog();d = null; // 去掉引用System.gc(); // 手动触发垃圾回收System.out.println("垃圾回收器已经被调用。");}
}
运行结果:
- 调用
System.gc()
后,垃圾回收器被唤醒。 - 输出内容:
垃圾回收器已经被调用。 Dog对象即将被垃圾回收!
这说明垃圾回收器触发了 finalize()
方法,但程序不会等待 finalize()
执行完成后才继续。
final 和 finalize 的区别
两者名字相似,但功能完全不同:
-
final:
- 修饰类:类不能被继承。
- 修饰方法:方法不能被重写。
- 修饰变量:变量一旦赋值,不能再改变。
-
finalize:
这是一个方法,用于对象销毁前的资源释放。可以通过重写finalize()
方法,定义对象被回收时的自定义逻辑。
常见问题解析
Q1:为什么 finalize()
默认没有代码?
Object
类中的 finalize()
方法默认是空实现,因为不是所有对象都需要自定义销毁逻辑。
Q2:为什么手动调用垃圾回收器才看到 finalize()
调用?
垃圾回收器的执行时机由 JVM 决定,System.gc()
只是一种“建议”垃圾回收器运行的方法,并不能保证立即回收对象。
Q3:实际开发中是否经常用 finalize()
?
很少。finalize()
更像是垃圾回收机制的补充,而不是主流解决方案。现代开发中,通常使用更可靠的工具如 try-with-resources
或手动释放资源代替。
总结
finalize()
的作用:清理即将被销毁的对象,释放资源。- 调用时机:当垃圾回收器发现对象无引用且准备回收时。
final
和finalize
的区别:前者用于修饰类、方法和变量,后者是对象销毁前的“善后”方法。- 开发建议:除非有明确需求,否则尽量避免重写
finalize()
方法,优先考虑更现代的资源管理方式。
用一句话记住:finalize()
是对象离开堆内存的告别礼,但不是每次离别都需要繁琐的仪式!
最后说一句(求关注,求赞,别白嫖我)
最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。
这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软
本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享
求一键三连:点赞、分享、收藏
点赞对我真的非常重要!在线求赞,加个关注我会非常感激!