如何确保始终调用finalize()(在Java练习中思考)

Mat*_*s17 15 java garbage-collection finalize

我正在慢慢地完成Bruce Eckel的Thinking in Java第4版,以下问题让我感到难过:

使用finalize()方法创建一个打印消息的类.在main()中,创建一个类的对象.修改上一个练习,以便始终调用finalize().

这是我编码的:

public class Horse {
    boolean inStable;
    Horse(boolean in){
        inStable = in;
    }   
    public void finalize(){
        if (!inStable) System.out.print("Error: A horse is out of its stable!");
    }
}
public class MainWindow {
    public static void main(String[] args) {
        Horse h = new Horse(false);
        h = new Horse(true);
        System.gc();
    }
}
Run Code Online (Sandbox Code Playgroud)

它创建一个Horse布尔值inStable设置为的新对象false.现在,在该finalize()方法中,它检查是否inStablefalse.如果是,则打印一条消息.

不幸的是,没有打印消息.由于条件评估为true,我的猜测是finalize()首先没有被调用.我已经多次运行该程序,并且已经看到错误消息只打印了几次.我的印象是,当System.gc()调用时,垃圾收集器将收集任何未引用的对象.

谷歌搜索一个正确的答案给了我这个链接,它提供了更详细,更复杂的代码.它采用了我以前从未见过的方法,如System.runFinalization(),Runtime.getRuntime()System.runFinalizersOnExit().

是否有人能够让我更好地了解如何finalize()工作以及如何强制它运行,或者让我了解解决方案代码中正在完成的工作?

Mar*_*ers 16

当垃圾收集器找到一个符合收集条件但有一个的对象时,finalizer它不会立即解除分配.垃圾收集器尝试尽快完成,因此它只是将对象添加到具有挂起终结器的对象列表中.稍后在单独的线程上调用终结器.

您可以通过System.runFinalization在垃圾回收后调用该方法来告诉系统立即尝试运行挂起的终结器.

但是如果你想强制终结器运行,你必须自己调用它.垃圾收集器不保证将收集任何对象或将调用终结器.它只是"尽力而为".但是,您很少需要强制终结器在实际代码中运行.

  • 当然,这是你应该[首先避免终结者]的部分原因(http://books.google.com/books?id=ka2VUBqHiWkC&pg=PA27&lpg=PA27&dq=effective+java+avoid+finalizers&source=bl&ots = yYGkMgn-QZ&SIG = o66EY94GVzB3uvNOvj9eLhdI35k&HL = EN&SA = X&EI = 0nsxUPeHHILp0gHx1oBI&VED = 0CGMQ6AEwAg#v = onepage&q =有效%20java%20avoid%20finalizers&F = FALSE). (3认同)
  • 我想我现在明白了.我咨询了使用`System.gc(); System.runFinalization();`这在我尝试时有效.我假设**System.gc()**需要在**System.runFinalization()**之前调用,因为它基本上将对象"标记"为"to-finalize",这样当我运行System.runFinalization时(),它有一个实际运行的对象.是这种情况,还是我的观察结果不准确? (2认同)
  • @ MattDs17:这可能是你的特定JVM实现的方式,但它没有指定以这种方式工作. (2认同)
  • “但是,您很少需要强制终结器在实际代码中运行。” 那只是因为缺乏保证意味着终结器对于任何关键的事情本质上都是毫无价值的,比如写入数据或释放系统锁。如果终结器确实有效,那么它们将有大量用途。 (2认同)