如果在完成调用期间保存对当前对象的引用会发生什么?例如:
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
对象是否被垃圾收集?当您稍后尝试访问bar.REFERENCE
时会发生什么?
答案 0 :(得分:12)
该对象不是垃圾回收。这被称为“物体复活”。
你必须小心,一旦调用终结器,gc就不会再次调用它,在某些像.NET这样的环境中,你可以重新注册终结器,但我不确定java
答案 1 :(得分:9)
如果你绝对必须复活对象,这篇JavaWorld文章建议创建一个新的实例,而不是复活正在最终确定的实例,因为如果最终确定的实例有资格再次收集它,它将被简单地收集(终结者赢了'再次运行。)
答案 2 :(得分:6)
这种事情是为什么不鼓励使用finalize()
的原因。
答案 3 :(得分:2)
因为Java是一种安全的语言和平台,所以内存不会被释放。相关联的PhantomReference
也不会在ReferenceQueue
时排队。 VM只会在对象上调用finalize
一次。 JVM规范中有一个很好的状态图。
通常,如果您使用终结者,则应将声明保留为@Override protected void finalize() throws Throwable
,以免干扰API。甚至可以更好地使用受保护的终结器,如Effective Java 1st Ed。
当普林斯顿的一个小组使用它从不受信任的代码构建自定义ClassLoader
时,这个特殊的技巧成为了圣何塞水星的头条新闻(无论如何)。尽管规范已经略微收紧(Object
构造函数必须在调用终结器之前正常执行 - 在J2SE 5.0中指定,在Java SE 6中实现),但这仍然是一个问题区域。如果您正在设计API,请确保敏感类不能成为子类并为您节省很多麻烦。
答案 4 :(得分:1)
可以在finalize()
实例上显式调用foo
方法,或者当垃圾收集器尝试回收该对象占用的存储时,可以调用它。
如果bar
是有效实例,则会将REFERENCE
字段设置为foo
实例。从垃圾收集器的角度来看,这会增加foo
的引用计数。
如果在finalize()
方法中抛出异常(例如由NullPointerException
bar
null
导致{{1}}),则终结过程将终止。
N.B。正如其他人指出的那样......你的例子肯定是值得避免的。