Consider this snippet:
class Test1 {
private static Test1 instance;
@NonNull private final Date date1;
@NonNull private final Date date2;
Test1() throws Exception {
this.date1 = new Date();
Test1.instance = this;
if (true) {
throw new Exception();
}
this.date2 = new Date();
}
public void dump() {
System.out.println("date1: " + date1);
System.out.println("date2: " + date2);
}
static void test() {
Test1 t1 = null;
try {
t1 = new Test1();
} catch (Exception e) {
e.printStackTrace();
}
Test1.instance.dump();
assert t1 == null;
}
}
Test1's constructor always throws an exception right after assigning itself to a static field. That field keeps a reference to a partially initialized object: an object who's date2
field is null
, even though it's declared @NonNull
and final
.
The test()
function can't directly get a reference to the generated t1. After the catch
block, t1 is null.
And yet, Test1.instance is just fine, and calling its dump()
function shows that date1
is initialized but date2
is null
.
What's going on here? Why can I keep a reference to an object that is really in an illegal state?
EDIT
That fact that t1
is null is obvious (unlike In Java what happens when an object fails to be instantiated?). This question is about the state of the object that managed to get stored in the static field.
Consider the bytecode for the following class:
class Foo {
public static void main(String[] args) {
new Foo();
}
}
Bytecode:
class Foo {
Foo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class Foo
3: dup
4: invokespecial #3 // Method "<init>":()V
7: pop
8: return
}
You can see from this that creation of the new instance and the invocation of the constructor are separate (lines 0 and 4 in main
).
So, even if it is not fully initialized, the instance exists; and you can assign a reference to that instance to another reference.
Assigning the instance to a static field before it is fully initialized is an example of unsafe publication, and you should (obviously) avoid it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With