为什么没有调用finalize()?

时间:2013-11-08 22:06:30

标签: 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 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");
        }
    }
}

2 个答案:

答案 0 :(得分:5)

仅在GC销毁并最终确定对象时调用finalize()方法,该方法在最后一次引用对象被丢弃后的某个未定义的时间点发生。如果永远不会释放该对象(例如,您仍然有对它的引用),则永远不会调用finalize()

另外请记住,当 finalize()被调用时,你无法控制,或者甚至根本不会被调用。 See general description of Object.finalize()

即使System.gc()也无法保证强制GC执行任何操作。这只是对JVM的一个建议。 See general description of System.gc()

通常,如果您发现自己试图像这样操作GC以执行这些类型的检查,通常会有更好的方法。这是对finalize()和GC的不当使用。

例如,如果您正在尝试检查假定的条件是否为真,请考虑在适当的位置使用assert(但要预先警告:assert不能替代功能{{1}它只是在设计时自我记录和测试条件。)

如果应用程序的更高级别功能的一部分是在退出之前验证条件是否为真,那么您应该在退出之前明确验证条件是否为真,例如:在你的情况下:

if

除了能够尝试从错误中恢复之外,显式检查还可以让您完全控制它何时发生。

更新:MadProgrammer在下面的评论中提到的另一个好选择是使用shutdown hook,如果这适合你。如果您的应用程序具有多个您无法消除或控制的退出点,那么这将提供一种在关闭时退出代码的简洁方法。

对于更复杂的应用程序,顺便提一下,您会发现测试策略,如单元测试等,当与良好的模块化设计(例如明确定义的前置条件,后置条件,不变量)相结合时,可以提供完整的应用程序逻辑测试要求自我测试成为应用程序正常运行的一部分。并不是说后者有什么问题,特别是在简单的应用程序中,但是你可能有兴趣了解它以供将来参考。

答案 1 :(得分:2)

根据JLS 12.6. Finalization of Class Instances

Java编程语言没有指定调用终结器的时间,只是说它会在重用对象的存储之前发生。