在Java中什么情况下应该使用finalize()方法?

4

什么时候应该在Java中使用finalize()方法?

如果我们想在finalize()方法中关闭连接,那么最好使用下面的代码,因为等待GC调用finalize()方法然后释放连接是没有意义的。

try{
// Connection creation
}finally{
//close connection
}

那么问题是,finalize() 方法今天是否有任何相关性?


4
“finally” 和 “finalize” 是完全不同的东西。 - Paul Tomblin
1
回答你的问题,不,我在近15年的Java开发中从未实现过finalize方法。 - Paul Tomblin
1
@PaulTomblin 是的,你说得对,我在这里尝试展示的是在 finalize() 方法中关闭连接的替代方法。最好我在 finally 块中关闭连接,而不是等待 GC 调用 finalize() 然后释放我的连接。使用 finally{},我可以控制何时释放连接。希望我表达清楚了。 - Jyotirup
那么我接下来的问题是,它在今天的情境中有什么相关性? - Jyotirup
可能是Clean up code in finalize() or finally()?的重复问题。 - Perception
5个回答

7
通过显式调用方法释放资源确实更好。finalizer 不一定会被及时或完全地调用,并且它们会增加性能开销。
但是,如果客户端忘记显式释放资源,则仍可以使用 finalizer 作为安全网来释放资源。
来自 Joshua Bloch 的《Effective Java》第二版中的主题“避免使用 finalizer”:
【D】除了作为安全网或终止非关键本地资源外,不要使用 finalizer。在那些极少数情况下使用 finalizer 时,请记住调用 super.finalize。如果您将 finalizer 作为安全网使用,请记得从 finalizer 记录无效使用。

2
通常我会在finalize方法中添加断言(并配置虚拟机使其在关闭时运行finalizer),以确保所有资源都被正确处理。在开发过程中捕获错误很好,但绝不应该在生产环境中使用。 - Voo

2

我所能想到应用finalize()方法的唯一场景是:

假设您在类中有一个静态资源(成员),并且希望在卸载类时对该资源进行一些清理、完成或日志记录,则需要重写finalize()方法并执行所有相关操作。


4
如果您拥有一个静态资源,当类的实例被收集时,肯定不希望每次都将其卸载。如果需要在关闭或其他时间释放静态资源(以及所有资源),请显式地执行此操作。这至少会起作用,与使用finalize方法相反。 - Voo
如果你的类实际上是一个singleton对象,在应用程序的生命周期中只加载和卸载一次(在关闭时),而你的应用程序恰好是一个POJO,你没有任何框架提供的关闭/销毁钩子,那该怎么办? - anubhava
我同意@Voo的观点,即使一个类是单例,你最好明确地打开()和关闭()资源,而不是依赖于finalize()被调用。 - eldjon

1
短答案是永远不要使用Finalize()。Finalize()存在许多微妙的问题,并且会大大减慢垃圾回收。
长答案是,在开发过程中,也许你想检查重要的连接、文件、套接字或其他资源是否已关闭,如果没有关闭,则记录警告,以便开发人员可以调查并正确修复问题。

0

finalize()不仅释放像套接字这样的资源,还管理内存。理论上讲,在代码中您不需要显式调用finalize()。它会在适当的时间由虚拟机执行。


在什么情况下应该重写finalize()方法? - Jyotirup
@Jyotirup 我以前从未实现过 finalize()。我认为finalize()函数很像 C++ 中的 destructor。如果您要重写它,那么肯定与资源释放有关。然而,大多数情况下 JVM 会帮助您正确地完成它。快速搜索给了我这个链接 http://www.google.com.hk/#hl=zh-CN&newwindow=1&safe=strict&sa=X&ei=2_T9ToWFCMqTiQeT1sntCg&ved=0CBkQvwUoAQ&q=when+to+override+finalize+java&spell=1&bav=on.2,or.r_gc.r_pw.,cf.osb&fp=a828595b5987e1c0&biw=1308&bih=596,我认为前三个链接可能会有所帮助。 - Summer_More_More_Tea
3
@Summer finalize与C++中的析构函数绝对不相似。析构函数是确定性的,这使它们在RAII方面非常有用。finalize存在一些问题,最重要的是除了查找错误之外几乎没有任何用处。最好不要使用它们-特别是如果您不理解底层发生了什么(即JVM何时运行finalizer以及其后果)。 - Voo

-1
实际上,finalize() 方法不应该被使用,特别是不应该用于清理资源。如果已经获取了某个资源,从性能的角度来看,最好显式地释放该资源,而不是等待 JVM 调用 finalize()。你无法预见 JVM 何时会调用 finalize(),如果你已经完成了对资源的使用,那么你会不必要地持有它更长的时间。我曾经看到有人在 finalize 方法中将变量置为 null,这是另一种不良实践,因为它通过完全不必要的代码行扩展了 GC 周期,从而减慢了程序的速度。GC 能够很好地处理死亡对象的清理过程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接