From my knowledge, when JVM is loading and generating code for A's clinit, if it encounters an unresolved class B, the compiler will first emit a method call to JVM internal to initialize B, then compile the method call/field use of B normally. So at run-time, B is ensured to be initialized before its field or method is used.
Please correct me if I made any mistake in the above.
Then I don't understand how JVM deal with a situation like below.
public class A {
public static A a = new A(B.b);
public A(B b) {
a = null;
}
public static void main(String[] args) {
System.out.println(a == null);
}
}
public class B {
public static B b = new B(A.a);
public B(A a) {}
}
Could someone explain how these two classes get initialized since they both need the other part to be initialized first? And why the main method in A returns false, since the static field a should be set null in A's constructor?
The second question is easy; the order of operations for the static initialization of A
is: B.b
is evaluated, new A(B.b)
is evaluated (setting a
to null
), a
is assigned new A(B.b)
. If any other instances of A
were created, then a
would be null. I think this should be easy to see without detailed knowledge about class initialization.
The first question is a bit more involved. The relevant chapter in the JLS is chapter 12 on execution. The basic idea is this: first a class is loaded, then it is linked, then it is initialized. As part of the linking, the class is prepared; this is when its static fields are created and set to their default values, which is null
for references (JLS 12.3.2) -- this happens before static
initalization.
So things happen in this order: A
is loaded and linked, so a
is initialized to null
. Then the static initializer runs, so new A(B.b)
needs to be evaluated. Now B
is loaded and linked, and its static initializer runs, and new B(A.a)
is evaluated, and at this point a
is null
and nothing special happens. Then A
's constructor runs and the newly created object is assigned to a
.