Java面试必考:finalize()方法到底什么时候被调用?揭秘垃圾回收背后的秘密!

软件求生 2025-02-19 09:44:30



大家好呀,我是小米!今天带来一篇技术干货,讲解一个面试中常见的Java面试题——finalize()方法到底什么时候被调用?析构函数(finalization)的目的又是什么?

这道问题听起来是不是有点像一块大石头,压得你喘不过气?别担心,今天我们就用轻松愉快的方式,给大家解开这道谜团。坐稳了,小米给你带来一场生动的面试题大揭秘之旅!

finalize()方法介绍

首先,我们得先了解什么是finalize()方法。finalize()方法是Java中的一个特殊方法,它属于java.lang.Object类,意味着所有Java类都继承了这个方法。说白了,它是Java中用于处理对象销毁前的一项清理工作的一种机制。每当对象在垃圾回收器(GC)准备回收的时候,如果对象重写了finalize()方法,Java虚拟机(JVM)会在对象被销毁前自动调用它。

你可以把finalize()想象成是一位临别赠言的老朋友,在你离开之前会悄悄对你说“再见”,并为你收拾最后的残局。好比一个工厂里的清洁工,在机器停止运作后,清理机器周围的垃圾一样——这就是finalize()的作用!

你会发现,finalize()方法和普通方法有一些特殊之处。首先,它是protected的,而不是public的,这就意味着它不能被外部类直接调用。其次,它接受Throwable异常,因此如果你在finalize()方法中抛出了异常,它不会影响到程序的执行。

finalize()方法什么时候被调用?

接下来,我们最关心的一个问题是:finalize()方法到底什么时候会被调用?

很多小伙伴可能会认为,finalize()方法会在对象被销毁时立即被调用,但是实际上,Java的垃圾回收机制是非确定性的,也就是说,什么时候对象会被销毁,什么时候finalize()方法会被调用,是由JVM的垃圾回收器(GC)来决定的。

垃圾回收器会定期检查堆内存,找到不再被引用的对象,并标记它们为垃圾对象。当垃圾回收器准备清理对象时,Java虚拟机会先调用这些对象的finalize()方法。如果对象没有在finalize()方法中进行适当的资源释放工作,那么这些资源就会被JVM管理的垃圾回收器自动清理。

然而,finalize()方法的调用并不是即时的,它会等到垃圾回收器准备销毁对象时才会调用。因此,并不能保证finalize()会立即在对象销毁之前被调用。

举个简单的例子:

在上述代码中,我们通过System.gc()强制请求垃圾回收。但是,调用System.gc()并不意味着垃圾回收立刻会发生,垃圾回收器会根据需要进行回收,并在对象被销毁之前,调用finalize()方法。

为什么需要finalize()?析构函数的目的是什么?

说到这里,很多人可能会问:既然垃圾回收器会自动清理对象,那为什么还需要finalize()方法?析构函数的目的是什么呢?

好问题!让我们从两个方面来思考这个问题:

1. 资源的管理与清理

在开发过程中,有时候我们可能会创建一些特殊的资源,比如文件句柄、数据库连接、网络连接等。这些资源在使用后是需要及时释放的,否则可能导致资源泄漏。

垃圾回收器会自动管理对象的内存空间,但对于一些特殊资源,它并不会处理。例如,如果你打开了一个文件,JVM的垃圾回收器并不会关闭它,这时就需要手动清理。finalize()方法可以用来释放这些非内存资源,比如关闭文件流、网络连接等。

在这个例子中,我们通过finalize()来确保在对象被回收时,打开的文件资源能得到正确的释放。

2. 作为最后一道安全防线

有时候,即使我们写得再小心,也会有忘记清理资源的情况发生。finalize()方法可以看作是最后一道安全防线,它确保在对象生命周期结束时,不会留下遗憾。即便我们忘记了释放某些资源,finalize()方法也可以补救,进行最后一次的清理工作。

finalize()方法的缺点

虽然finalize()方法能帮助我们释放资源,但它也并非完美无缺,存在一些缺点。以下是几个常见的缺点,大家需要特别注意:

1. 不确定性

正如之前所提到的,finalize()方法的调用时机是由垃圾回收器决定的。我们无法控制它何时执行,因此无法确保在某个特定时刻释放资源。如果资源的释放时机非常重要,那么依赖finalize()显然不靠谱。

2. 性能开销

垃圾回收器在回收对象时,会先调用对象的finalize()方法。这一过程会增加额外的性能开销,因为垃圾回收器需要检查每个对象是否重写了finalize()方法,并调用它。尤其是当对象数量非常庞大时,性能开销会变得非常明显。

3. 不能抛出异常

在finalize()方法中,我们不能抛出异常。即使抛出异常,它也不会影响到垃圾回收器的执行。如果抛出异常,垃圾回收器会继续执行回收过程。因此,finalize()中的异常往往无法被捕获和处理,这在一些特殊情况下可能导致意外结果。

finalize()的替代方案

由于finalize()方法的局限性,Java引入了其他更为可靠的资源管理方法。其中最常见的就是try-with-resources语句,它通过自动关闭资源来避免资源泄漏。

在上面的代码中,try-with-resources语句确保了即使在异常发生时,FileReader对象也会在作用域结束时自动关闭,无需显式调用finalize()。

总结

今天我们详细聊了finalize()方法的作用、何时被调用以及它的优缺点。简单来说,finalize()方法在对象生命周期的最后阶段被调用,用来释放资源并执行清理工作。它是Java垃圾回收机制的一部分,但由于不确定性和性能开销,已经不再是资源管理的首选方法。为了更好地管理资源,我们可以使用try-with-resources语句来替代finalize(),让代码更简洁、性能更高效。

如果你正准备参加Java社招面试,希望你能将今天的内容牢牢记住,掌握这个面试技巧。你会发现,掌握了这类“技术小细节”,不仅能在面试中轻松应对,还能在实际开发中避免踩坑。

END

好啦,今天的分享就到这里。感谢大家的阅读,如果你喜欢这篇文章,不要忘记点赞、收藏、转发哦!有任何问题,欢迎在评论区留言,我们下期再见!

熬夜码字不易,一杯奶茶续命!看完文章别忘了顺手点开图片广告,让作者攒点奶茶基金,感激不尽!

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!

0 阅读:0
软件求生

软件求生

从事软件开发,分享“技术”、“运营”、“产品”等。