Yes, this behavior is clearly defined here .
In short, referring to this link
Initializing a class or interface consists of executing a method to initialize a class or interface <clinit>
...
A class or interface can only be initialized as a result of:
Execution of any of the instructions of the Java virtual machine new, getstatic, putstatic or invokestatic, which refers to a class or interface (§new, §getstatic, §putstatic, §invokestatic). All of these instructions refer to the class directly or indirectly through a link to a field or a link to a method.
After executing a new command, the reference class or interface is initialized if it has not yet been initialized.
After the getstatic, putstatic or invokestatic statement is executed, the class or interface that declared the allowed field or method is initialized if it has not already been initialized.
The first call to the java.lang.invoke.MethodHandle instance, which was the result of resolving the Java virtual machine method descriptor (§5.4.3.5) and has the form 2 (REF_getStatic), 4 (REF_putStatic), or 6 (REF_invokeStatic).
Calling some reflective methods in a class library (§2.12), for example, in the Class class or in the java.lang.reflect package.
Initializing one of its subclasses.
Its designation as the initial class when starting the Java virtual machine (§5.2).
The <clinit> method is a method (created by the compiler) that initializes static variables and has code that you put in a static block
In your case, when a static block of class B is executed (what <clinit> will do), it will have a getStatic requesting A.HOST . Thus, the initialization of A will start, and A.HOST initialized. This way you will read the correct value.