以我的经验,有一个唯一的原因要覆盖Object.finalize()
,但这是一个很好的理由:
放置错误日志记录代码,finalize()
如果您忘记调用时将通知您close()
。
静态分析只能捕获琐碎的使用场景中的遗漏,并且另一个答案中提到的编译器警告对事情的处理过于简单,您实际上必须禁用它们才能完成任何不重要的事情。(与我认识或从未听说过的任何其他程序员相比,我启用的警告要多得多,但我没有启用愚蠢的警告。)
最终确定似乎是确保资源不会被处置的一种很好的机制,但是大多数人以完全错误的方式看待它:他们将其视为备用的备用机制,这是“第二次机会”保护措施,可以自动节省资源。一天,通过处置他们遗忘的资源。这是完全错误的。做任何给定事情的方法必须只有一种:要么总是关闭所有内容,要么终结总是关闭所有东西。但是由于最终确定是不可靠的,因此不可能最终确定。
因此,有一个我称为“ 强制性处置”的方案,它规定程序员负责始终显式关闭实现Closeable
或的所有内容AutoCloseable
。(try-with-resources语句仍然算作显式关闭。)当然,程序员可能会忘记,所以这就是终结的作用,而不是像魔术仙子那样最终使事情正确的方法:如果发现终结,这close()
没有被引用,它不尝试调用它,正是因为(在数学上可以确定)成群的n00b程序员将依靠它来完成他们懒惰或缺乏思想的工作。因此,通过强制处理,当完成确定close()
没有被调用时,它会记录一条鲜红色的错误消息,告诉程序员用大写的大写字母来修复他的东西。
另一个好处是,有传言说“ JVM将忽略一个琐碎的finalize()方法(例如,一个不做任何事情就返回的方法,例如Object类中定义的方法)”,因此通过强制性处置,您可以避免所有终结处理通过像下面这样编码您的方法,整个系统的开销(请参阅alip的答案以获取有关此开销有多可怕的信息)finalize()
:
@Override
protected void finalize() throws Throwable
{
if( Global.DEBUG && !closed )
{
Log.Error( "FORGOT TO CLOSE THIS!" );
}
//super.finalize(); see alip's comment on why this should not be invoked.
}
其背后的思想Global.DEBUG
是一个static final
变量,其值在编译时是已知的,因此,如果为零,false
则编译器将针对整个if
语句根本不发出任何代码,这将使其成为一个琐碎的(空的)终结器,这反过来意味着您的类将被视为没有终结器。(在C#中,这将使用一个不错的#if DEBUG
块来完成,但是我们可以做的是Java,在Java中,我们在代码上付出了明显的简化,却增加了大脑的开销。)
有关强制性处置的更多信息,以及关于在点网中处置资源的更多讨论,请访问:michael.gr:强制性处置与“可处置性”可恶
finalize()
有些混乱。如果您实现了它,请确保它相对于同一对象上的所有其他方法是线程安全的。