When objects in Java are partially initialized ( an exception occurs in the constructor )
I've heard that it is possible to write some code like this
SomeClass obj = null;
try {
obj = new SomeClass();
} catch ( Exception e ) {
...
}
...
if ( obj != null ) { // here it holds true
...
}
Can somebody please explain, is that possible at all and under what conditions if we assume that constructor SomeClass may throw an Exception?
Another example:
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
public class Sample{
static class A {
public static A s;
pub开发者_开发百科lic A(Collection c) {
c.add(this);
s = this;
throw new RuntimeException();
}
}
@Test
public void testResource() throws Exception {
List l = new ArrayList();
A a = null;
try {
a = new A(l);
fail("Oops");
} catch (Throwable e) {
}
assertTrue(l.size() == 1);
assertNull(a);
assertNotNull(A.s);
assertNotNull(l.get(0));
}
}
First you declare and initialize a variable.
SomeClass obj = null;
In the following lines you (1) create a new instance and (2) store the reference.
try {
obj = new SomeClass();
} catch ( Exception e ) {
...
}
Now we assume, the instantiation (Step 1) fails and throws an exception: the JVM will continue in the next catch block that handles that exception. So step 2 will not be executed and the variable will keep its actual state.
Now is is possible that an instance has been initialized partially. Honestly, I don't know, that's JVM internal. But as nothing holds a reference to this partially initialized instance, it will be gc'd on the next occasion.
It's quite possible.
I'm not sure I understand your question though, you've answered it yourself: if the constructor throws an exception, obj could be null.
You can certainly write code like that, and it will compile and run just fine. But there will never be a case where obj
is "partially initialized". Either it will be, or it won't be. Specifically, if this line throws an Exception
:
obj = new SomeClass();
Then it is as if that line was never executed, as far as the value of obj
is concerned. You initialize obj
to null
prior to that line, so if an exception is thrown then obj
will still be null
. In that case the program will not go into the if
block at the end.
Or, if an exception is not thrown, then obj
will no longer be null
, and the code inside of the final if
block will be executed.
It is perfectly possible; look closer: if the constructor throws an exception, obj
will still be null
.
If the SomeClass
constructor throws an Exception obj
will be NULL.
For me the object is null even after calling constructor:
public static void main(String[] args) {
TestCls cls = null;
try {
cls = new TestCls("");
} catch (Exception e) {
e.printStackTrace();
}
if(cls == null)
System.out.println("hi");
}
public TestCls(String str) throws Exception{
throw new Exception();
}
Output:-
java.lang.Exception
hi
at TestCls.<init>(TestCls.java:57)
at TestCls.main(TestCls.java:48)
Conclusion: If the class constructor
throws an Exception
then the obj
will be NULL
.
The constructor could throw an Exception, just like any other call in Java could. For instance it may throw a NullPointerException if trying to call a method on a null reference. Consider the following example:
public class ConstructionTest {
static ConstructionTest obj;
public ConstructionTest() {
String s = null;
s.hashCode();
}
public static void main(String[] args) {
try {
obj = new ConstructionTest();
} catch ( Exception e ) {
System.err.println(e);
}
if ( obj != null ) {
System.err.println("Not Null");
} else {
System.err.println("Is Null");
}
}
}
As s is null in the Constructor a NullPointerException is thrown, so "Is Null" gets printed. There is no concept of a "partially constructed Object" - when you use new in Java it either works and you get the newly instantiated Object back or it doesn't work and you get the Exception.
精彩评论