3

If the constructor ends up with an exception, is the object created exactly the same with a normal one?

class A { static A o; A() throws Exception { o=this; throw new Exception(); } void f() { System.out.println("f(): entry."); }; static public void main(String[]args ) { try { A o =new A(); } catch (Exception e) { System.out.println("Exception: " + e); } A.o.f(); // Is it safe to use this object? } } 

This compiles and runs, and the output of this program is:

Exception: java.lang.Exception f(): entry. 
5
  • 1
    is it Java? have you even tried compiling it? Commented May 18, 2012 at 3:07
  • 1
    @DonLi, user331225 is pointing out that you're missing a } so your code sample will not compile. Commented May 18, 2012 at 3:10
  • 1
    (A very interesting question, by the way. I can't see why someone is asking it to be closed.) Commented May 18, 2012 at 3:23
  • 1
    @DonLi.. very interesting question.. my thoughts are that the object should be ready for gc after the exception.. but as it is referenced by a class member before it is gc-eligible.. it will not be gc'd.. so technically that object will be usable till the jvm has loaded the class A.. good job! Commented May 18, 2012 at 3:26
  • @user331225 -- There's nothing really that would make that object more or less eligible to be garbage-collected than any other object. If it's reachable it will persist. Commented May 18, 2012 at 3:33

2 Answers 2

3

If you catch the exception, the constructed object is never passed back to the caller, and the caller's result variable is not set. However, the static variable would, in theory, be set, and I can't see any reason why it would not be accessible.

Note, however, that method verification will not allow you to store this until after the super constructor is called, so this is not a "back door" into otherwise protected objects.

Since it's your object, "safe" is up to you.

[A little more detail: When the compiled version of your constructor is entered, the "raw" Java object is fully constructed -- no additional work is needed by the system to make it valid. The super constructor has not been called yet, however, and it's either up to you to explicitly make a super call or have the compiler insert the super call by default (which it will do at the start of the method if you don't have an explicit call). The "bytecode verifier" in the JVM has some very strict rules about what can happen in a constructor prior to calling the super constructor, and storing this to a static would be a definite no-no -- you'd get a VerifyError.]

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. What do you mean "a VerifyError" ?
@DonLi -- java.lang.VerifyError, on loading the class.
2
 A.o.f(); // Is it safe to use this object? 

It is a regular java object that will respond to method calls just as any other Java object. This is not a source of undefined behavior as far as the Java language is concerned.

That doesn't mean it's safe to use. Many classes' safety depends on their ability to maintain important invariants, and unexpected exceptions thrown during construction or critical operations often mean that those invariants do not hold so they are not safe to use.

Consider what happens if you subclass A

public class S extends A { boolean dirty; S() throws Exception { // Do work to maintain important security invariants. dirty = true; } void foo() { if (dirty) { System.out.println("clean"); dirty = false; } System.out.println("foo"); } public static void main(String... argv) { try { new S(); } catch (Exception ex) {} // Now A.o is an instance of S, but S's constructor // was never called. S s = (S) A.o; // works. s.foo(); // Never prints clean before printing foo. } } 

4 Comments

Surely the point of this question relates to the fact that the constructor returns abnormally (so the assignment in the try statement never sees the result), yet a reference to the object can still be obtained. You've not really addressed this with anything substantive (you're second paragraph skirts what I think is the OP's true issue).
@GregKopff, It is up to the asker to define "safe" but even though the asker did not supply a definition I answered for two common definitions -- it is not a source of undefined behavior, but is a common symptom when invariant violation has occurred.
where I think Hot Licks hit the nail on the head was the inclusion of the fact that you cannot use this unless the superconstructor has executed to completion. With that information, a discussion of safety of the child class makes more sense.
@GregKopff, in my example, this is leaked by super which is why S's constructor is never entered. And remember that Java does not do the progressive vtable setting that C++ does, so even though S's constructor is not entered, the resulting object is an instanceof S.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.