Java 为什么不调用finalize()?
我想用finalize检查终止条件,但finalize每次都不会执行。有人能告诉我为什么吗Java 为什么不调用finalize()?,java,finalize,Java,Finalize,我想用finalize检查终止条件,但finalize每次都不会执行。有人能告诉我为什么吗 public class Test { public static void main(String[] args) { Tank tank=new Tank(); tank.fill(); System.gc(); } } public class Tank { private boolean empt
public class Test
{
public static void main(String[] args)
{
Tank tank=new Tank();
tank.fill();
System.gc();
}
}
public class Tank {
private boolean emptied=true;
public void fill()
{
this.emptied=false;
}
public void empty()
{
this.emptied=true;
}
public Tank()
{
this.emptied=true;
}
protected void finalize()
{
if(this.emptied==false)
{
System.out.println("Termination Verification Error: Tank should be emptied");
}
}
}
依照
Java编程语言没有指定调用终结器的时间,只是说它将在重用对象的存储之前发生。根据
Java编程语言没有指定调用终结器的时间,只是说它将在对象的存储被重用之前发生。只有当GC销毁并终结对象时才会调用finalize()
方法,这发生在对对象的最后一次引用被丢弃后的某个未定义的时间点。如果对象从未被释放(例如,您仍然有对它的引用),则永远不会调用finalize()
还要记住,您无法控制何时调用finalize()
,或者是否会调用它
即使System.gc()
也不能保证强制gc执行任何操作。这只是对JVM的一个建议
通常,如果您发现自己试图像这样操纵GC以执行这些类型的检查,通常有更好的方法。这是对finalize()
和GC的不当使用
例如,如果您试图检查假定条件是真的,请考虑在适当的地方使用<代码> AsStAs<代码>(但预先警告:<代码>断言< /COD>不是函数<代码>的替换(如果);它仅是在设计时假定的自文档和测试条件)。 如果应用程序更高级别功能的一部分是在退出前验证条件是否为真,则应在退出前明确验证条件是否为真,例如,在您的情况下:
public static void main(String[] args)
{
Tank tank=new Tank();
tank.fill();
// check explicitly before terminating
if (!tank.empty())
System.err.println("Warning: Ending with non-empty tank!");
}
除了可以尝试从错误中恢复外,显式检查还可以让您完全控制何时发生错误
更新:另一个很好的选择,程序员在下面的评论中很有帮助地提出了,如果适合你的话,可以使用。如果您的应用程序有多个无法消除或控制的退出点,那么这将提供一种在关闭时退出代码的干净方法
顺便说一下,对于更复杂的应用程序,您会发现单元测试等测试策略与良好的模块化设计(例如,明确定义的前提条件、后条件、不变量)相结合,可以提供完整的应用程序逻辑测试,而无需将自检作为应用程序正常运行的一部分。并不是说后者有什么问题,特别是在简单的应用程序中,但您可能有兴趣了解它以供将来参考。只有当GC销毁并最终确定对象时才会调用finalize()
方法,这发生在对对象的最后一次引用被丢弃后的某个未定义的时间点。如果对象从未被释放(例如,您仍然有对它的引用),则永远不会调用finalize()
还要记住,您无法控制何时调用finalize()
,或者是否会调用它
即使System.gc()
也不能保证强制gc执行任何操作。这只是对JVM的一个建议
通常,如果您发现自己试图像这样操纵GC以执行这些类型的检查,通常有更好的方法。这是对finalize()
和GC的不当使用
例如,如果您试图检查假定条件是真的,请考虑在适当的地方使用<代码> AsStAs<代码>(但预先警告:<代码>断言< /COD>不是函数<代码>的替换(如果);它仅是在设计时假定的自文档和测试条件)。 如果应用程序更高级别功能的一部分是在退出前验证条件是否为真,则应在退出前明确验证条件是否为真,例如,在您的情况下:
public static void main(String[] args)
{
Tank tank=new Tank();
tank.fill();
// check explicitly before terminating
if (!tank.empty())
System.err.println("Warning: Ending with non-empty tank!");
}
除了可以尝试从错误中恢复外,显式检查还可以让您完全控制何时发生错误
更新:另一个很好的选择,程序员在下面的评论中很有帮助地提出了,如果适合你的话,可以使用。如果您的应用程序有多个无法消除或控制的退出点,那么这将提供一种在关闭时退出代码的干净方法
顺便说一下,对于更复杂的应用程序,您会发现单元测试等测试策略与良好的模块化设计(例如,明确定义的前提条件、后条件、不变量)相结合,可以提供完整的应用程序逻辑测试,而无需将自检作为应用程序正常运行的一部分。并不是说后者有什么问题,特别是在简单的应用程序中,但您可能有兴趣了解一下,以备将来参考。因为您仍然有一个对对象的引用,那么为什么您希望它是gc'd呢?因此,如果他们设置
tank=null
它应该可以工作吗?老实说,我从来没有在Java中使用过解构。一般来说,JVM不保证在对象销毁后直接执行终结器。因此,如果您有一些必须执行的终止代码,请使用自定义终止方法e。G通过实现Closeable
/AutoCloseable
接口。请参阅有效Java,第7项:避免终结器。@JasonSperske。在调用System.gc()
之前设置tank=null
(或者将其设置为其他值;要点是没有对感兴趣的对象的剩余引用),这将鼓励它工作。您仍然不能保证在调用GC()
时GC确实会运行,或者它实际上会丢弃