【问题标题】:Java 8 is this assertion about finalize method correct? [duplicate]Java 8 这个关于 finalize 方法的断言是否正确? [复制]
【发布时间】:2020-02-26 20:38:57
【问题描述】:

我一直在阅读 Kathy Sierra + Bert Bates 编写的OCA Java SE 8 Programmer I Exam Guide一书。

关于 finalize 方法的一些东西我不太明白。它在第 218 页上声明:

调用finalize()实际上可以导致保存对象免于删除。

稍后在第 222 页:

您可以在finalize() 中使对象不符合 GC 条件。

英语不是我的母语,但我在这两种情况下的理解是finalize() 方法可以防止对象被垃圾回收?是这样吗?还是我误解了?

【问题讨论】:

  • 如果您要在某处保存对 finalize 中对象的引用,我认为这会阻止它被 GC。

标签: java finalize


【解决方案1】:

嗯,没错。

finalize() 方法在 GC 决定应该删除对象时被调用,但这并不意味着对象将在 finalize 完成后立即被删除。

IT DOESN'T WORK THIS WAY:
_________________________
IF shouldBeRemoved(object)
   object.finalize();
   remove(object);

finalize 执行后,GC 将再次检查该对象是否仍应被删除。要符合删除条件,不应从任何可从根对象访问的对象中引用对象。

IT WORKS THIS WAY
_________________
LABEL
IF shouldBeRemoved(object)
    object.finalize();
    IF shouldBeRemoved(object)
        remove(object);
    ELSE
        GOTO LABEL

让我们想象以下情况:

class Foo {
    Application a;

    Foo(){};

    @Override
    public void finalize() {
        this.a = Application.getInstance();
    }
}

其中Application 是一个代表Application 的根对象的类。在这种情况下,由于a 仍然可以访问,所以之前符合删除条件的Foo 类的对象刚刚复活。

重要说明

你不能保证finalize会被调用,因为它需要另一个对象来处理finalize被调用的方法,所以如果堆上没有足够的可用空间,对象可能会被销毁无需致电finalize

【讨论】:

  • 如何将Application 实例分配给一个实例变量来保持同一个实例的可访问性?它没有将this 的引用分配给其他位置,所以我看不到如何通过它自己的实例变量访问该实例。
  • 关于“对象可能在不调用finalize的情况下被销毁”,这是错误的。另外,我不明白“它需要另一个对象来处理被调用的finalize 方法”。还有什么对象?这也不对。
【解决方案2】:

Finalize 是由 JVM 而不是用户调用的方法,此方法在对象被垃圾回收之前执行,您可以覆盖 finalize 方法在对象被释放之前进行清理操作,或者如书中所述有可能您可以防止对象被垃圾收集。

您可以参考下面的代码作为保存对象免遭垃圾回收的示例。

class Example { 

    static Example y; 

    void func() { 
        Example x = new Example(); 
    } 

    pubic void finalize() { 

        y = this; // Putting the reference id 
        // of the current object 
        // into the static variable y 

        System.out.println("The object won't be collected by the garbage collector"); 

    } 

    public static void main(String a[]) {
        func(); // function called 
    } 
}

【讨论】:

  • 是的,就像这个主题显示的那样。 dzone.com/articles/…
  • @chiperortiz 是的,当调用 finalize 方法时,您始终可以使用此关键字引用正在销毁的对象并从该特定对象执行您需要的任何操作,其中一种用法是复活。
【解决方案3】:

这实际上更多是理论上的事情:当对象不再被其他 live 对象引用时,它们就有资格进行垃圾回收。

因此:您可以尝试finalize() 中创建这样的引用。这在理论上会阻止对象被移除。

实际上有一个“模式名称”:object resurrection。现在,如果这是一种模式,或者更多的模式有待商榷。

(我个人:我永远不会那样做,而且我从来没有遇到过需要使用这种模式的情况)

【讨论】:

  • 除了这是一种在垃圾收集器启动并尝试收集有问题的对象时调用某些逻辑的方法,这实际上与简单地存储对所述对象的“全局”引用没有什么不同,对吗?
  • @Fureeish 请记住,finalize() 只被调用一次(如果它被调用的话)。再次引用该对象后,再取消引用,finalize() 方法不再被调用,该对象将被直接丢弃。
  • @Fureeish 好吧,当您在某个“全局存储”中添加引用时,您会在之前 的某个时间点执行此操作。所以理论上,那个对象 never 符合条件,因此它的 finalize() 永远不会被调用。
  • @manouti 不会再次调用该对象的 finalize() 方法,但它不必重新启动 this 实例,但可以在完成状态下重新启动只能由该对象访问的另一个对象。它可以用finalize() 存储到另一个对象中,以任意次数复活它。但事实上,finalize()的调用已经是复活了。将无限循环放入其中,对象将永远存在,无需存储全局引用。只要你有终结器线程和具有非平凡finalize()所有对象保持活动状态,就经常这样做。
猜你喜欢
  • 2016-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 1970-01-01
  • 2011-07-07
  • 1970-01-01
相关资源
最近更新 更多