Java 为什么不调用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

我想用finalize检查终止条件,但finalize每次都不会执行。有人能告诉我为什么吗

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确实会运行,或者它实际上会丢弃