Yes that behavior is well defined here.
In short, citing from that link
Initialization of a class or interface consists of executing the class or interface initialization method <clinit>
...
A class or interface may be initialized only as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references the class or interface (§new, §getstatic, §putstatic, §invokestatic). All of these instructions reference a class directly or indirectly through either a field reference or a method reference.
Upon execution of a new instruction, the referenced class or interface is initialized if it has not been initialized already.
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
The first invocation of a java.lang.invoke.MethodHandle instance which was the result of resolution of a method handle by the Java Virtual Machine (§5.4.3.5) and which has a kind of 2 (REF_getStatic), 4 (REF_putStatic), or 6 (REF_invokeStatic).
Invocation of certain reflective methods in the class library (§2.12), for example, in class Class or in package java.lang.reflect.
The initialization of one of its subclasses.
Its designation as the initial class at Java Virtual Machine start-up (§5.2).
The <clinit>
method is the method (created by the compiler) that initializes static variables and has the code that you put in the static
block
In your case, when the static
block of class B
runs (which is what <clinit>
will do), it will have a getStatic
opcode, requesting A.HOST
. So the initialization of A
will be triggered, and A.HOST
initialized. So you will read the proper value.