【问题标题】:Can finalize be called after a constructor throws an exception?构造函数抛出异常后可以调用finalize吗?
【发布时间】:2013-01-23 15:33:27
【问题描述】:

如果对象的构造函数出现异常,是否有任何关于是否使用finalize() 清理对象的详细信息。

当这个方法被调用是出了名的错误定义。根据手册:

Java 编程语言不保证哪个线程会 为任何给定对象调用 finalize 方法。可以保证, 但是,调用 finalize 的线程不会持有任何 调用 finalize 时用户可见的同步锁。如果 finalize 方法抛出未捕获的异常,异常是 被忽略并且该对象的终结终止。

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#finalize%28%29

我无法以这种方式触发 finalize 方法。有谁知道它是否被保证不被调用,或者在某些情况下在构造函数初始化对象失败后调用它(这是一个异常)。

我问这个是因为我有一个不能清理两次的对象。我试图了解在抛出异常之前清理是否安全,或者我是否必须为finalize() 留下标记才能有效地跳过并且什么也不做。

【问题讨论】:

  • +1 我怀疑这是你需要检查的东西,因为不同的 JVM 可能会有不同的行为。
  • 使用finalize 是邪恶的。
  • @Peter JLS 非常具体,一旦 [base] 对象的构造函数成功完成,对象就可以完成。
  • @JasonPyeron 很好的说明。

标签: java exception constructor


【解决方案1】:

我的测试表明可以

public class Test1 {

    Test1() {
        throw new RuntimeException();
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalized");
    }

    public static void main(String[] args) throws Exception {
        try {
            new Test1();
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        System.gc();
        Thread.sleep(1000);
    }
}

打印

java.lang.RuntimeException
    at test.Test1.<init>(Test1.java:13)
    at test.Test1.main(Test1.java:24)
finalized

它在 Java HostSpot Client VM 1.7.0_03 上

【讨论】:

  • 这很有帮助!您能否编辑您在哪个 JVM 上尝试过的答案,我会接受。非常感谢!
  • 这是因为隐含的 super() 没有抛出异常。
【解决方案2】:

根据 JLS 的12.6.1. Implementing Finalization 部分:

直到对象 o 的构造函数调用 o 上的 Object 的构造函数并且调用成功完成(即没有抛出异常),对象 o 才能最终确定。

如果您的构造函数在 Object 构造函数完成之后抛出异常,那么您的对象应该是可终结的,因此仍然可以调用 finalize()

12.5. Creation of New Class Instances 部分中有一个很好的示例逐步完成对象构造,它准确显示了何时调用 Object 构造函数。

【讨论】:

  • 这意味着在类 X X(){super();} 中,对 Object 的 super() 调用无一例外地完成。 Object 类具有注册堆分配的胶水代码,由 new 分配,用于垃圾回收。
  • 值得一提的是,上述备注(finalizable的定义)1st出现在JLS的第3版(Java 1.5)中,但Java 1.5仍然允许finalizer即使 Object 构造函数从未被调用过(请参阅 here)。此错误仅在 Java 1.6 中修复。
  • @Bass 甚至还有一个 JVM 选项来启用旧行为,不幸的是,我不记得它的确切名称。
  • @Holger 谢谢!我相信是RegisterFinalizersAtInit
【解决方案3】:

为了更清楚地展示:

public class Test1 {

    public static class LifeBoat extends RuntimeException
    {
        private Test1 passenger;
        public Test1 getPassenger(){return passenger;}
        public LifeBoat(Test1 passenger){this.passenger=passenger;}
    }

    Test1() {
        super(); //once this is finished, there is an Object to GC per JLS 12.6.1. 
        throw new LifeBoat(this);
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalized");
    }

    public static void main(String[] args) throws Exception {
        try {
            new Test1();
        } catch (LifeBoat e) {
            Test1 obj;
            obj=e.getPassenger();
            System.out.println(obj);
        }
        System.gc();
        Thread.sleep(1000);
    }
}

打印

java.lang.RuntimeException
    at test.Test1.<init>(Test1.java:13)
    at test.Test1.main(Test1.java:24)
test.Test1@6dc8f3cd
finalized

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 2011-11-04
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    相关资源
    最近更新 更多