18

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

众所周知,何时调用此方法时定义不正确。根据手册:

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

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

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

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

4

3 回答 3

12

我的测试表明它可以

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 客户端 VM 1.7.0_03

于 2013-01-23T15:42:59.397 回答
10

根据第12.6.1 节。实现JLS 的最终确定:

一个对象 o 在其构造函数调用 o 上的 Object 的构造函数并且该调用已成功完成(即没有抛出异常)之前是不可终结的。

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

在第12.5节中有一个很好的例子来逐步完成对象构造。创建新类实例,准确显示何时调用 Object 构造函数。

于 2013-01-23T15:51:02.840 回答
1

为了更清楚地证明:

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
于 2014-06-13T14:33:13.417 回答