Can finalize be called after a constructor throws an exception?

二次信任 提交于 2019-12-30 03:49:05

问题


Are there any details on whether or not an object is cleaned up using finalize() if that object's constructor thew an exception.

When this method is called is notoriously ill defined. According to the manual:

The Java programming language does not guarantee which thread will invoke the finalize method for any given object. It is guaranteed, however, that the thread that invokes finalize will not be holding any user-visible synchronization locks when finalize is invoked. If an uncaught exception is thrown by the finalize method, the exception is ignored and finalization of that object terminates.

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

I've not been able to trigger the finalize method in this way. Does anyone know if it is garunteed NOT to be called or if it is in some cases called after the constructor failed to initialize the object (thew an exception).

I ask this because I have an object which must not be cleaned up twice. I'm trying to understand if it is safe to clean up before throwing the exception or if I must leave a marker for finalize() to effectively skip and do nothing.


回答1:


My test shows that it can

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);
    }
}

prints

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

it is on Java HostSpot Client VM 1.7.0_03




回答2:


According to section 12.6.1. Implementing Finalization of the JLS:

An object o is not finalizable until its constructor has invoked the constructor for Object on o and that invocation has completed successfully (that is, without throwing an exception).

If your constructor throws an exception after the Object constructor completes, then your object should be finalizable, so finalize() could still be called.

There's a good example stepping through object construction in section 12.5. Creation of New Class Instances that shows exactly when the Object constructor is called.




回答3:


To demonstrate more clearly:

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);
    }
}

prints

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


来源:https://stackoverflow.com/questions/14483279/can-finalize-be-called-after-a-constructor-throws-an-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!