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.