Class initialization is the last stage of the class loading process. It is only in the initialization phase that Java program code in the class is actually executed. The virtual machine specification strictly specifies that class initialization must be performed immediately in four cases:
In the case of the new, getstatic, putstatic, and invokestatic bytecode commands, if the class has not been initialized, you must first trigger its initialization. The most common Java code scenario for generating these four commands is: when an object is instantiated using the new keyword, when a static field of a class is read or set (modified by final, except for static fields that have put the results into the constant pool during the compilation period) and when calling a static method of a class. When you use the Java. lang. refect package method to call a class for reflection, if the class has not been initialized, you must first trigger its initialization. When initializing a class, if you find that the parent class has not been initialized, you must first trigger the initialization of the parent class. When a virtual machine is started, you must specify a primary class to be executed. The virtual machine runs the primary class first. The virtual machine requires that only these four conditions will trigger class initialization, which is called active reference to a class. In addition, all referenced classes will not trigger initialization, which is called passive reference. The following are examples of passive references.
1. reference the static fields in the parent class through the subclass. In this case, the reference to the subclass is passive reference. Therefore, the subclass is not initialized and only the parent class is initialized.
Class Father {public static int m = 33; static {System. out. println (parent class initialized);} class Child extends Father {static {System. out. println (subclass initialized);} public class StaticTest {public static void main (String [] args) {System. out. println (Child. m );}}
The output result is as follows:
Parent class initialized
33
For static fields, only the class that directly defines this field is initialized. Therefore, its subclass is used to reference the static fields defined in the parent class, only the initialization of the parent class is triggered, but the initialization of the Child class is not triggered.
2. A constant is stored in the constant pool of the class that calls it during the compilation phase. In essence, it does not directly reference the class that defines the constant. Therefore, initialization of the class that defines the constant is not triggered.
Class Const {public static final String NAME = I am a constant; static {System. out. println (initialize the Const class);} public class FinalTest {public static void main (String [] args) {System. out. println (Const. NAME );}}
The output result is as follows:
I am a constant
Although the constant NAME of the const class is referenced in the program, in the compilation phase, the constant value "I am a constant" is stored in the constant pool of the FinalTest class that calls the Const class. the reference of NAME is actually converted to the reference of the FinalTest class to its own constant pool. That is to say, in fact, the FinalTest Class file does not have a Const Class symbolic reference entry, and there is no connection between the two classes after being compiled into the Class file.
3. The class is referenced through array definition, and class initialization is not triggered.
Class Const {static {System. out. println (initialize the Const class);} public class ArrayTest {public static void main (String [] args) {Const [] con = new Const [5];}
After execution, no information is output, indicating that the Const class is not initialized.
However, this code triggers the initialization of another class named "LLConst", which is automatically generated by a virtual machine and directly inherited from java. lang. the Object subclass is triggered by the bytecode instruction newarray. Obviously, this is the initial initialization of the array reference type, and the elements in this array only contain a reference to the Const class, it is not initialized. If we add the instantiation code for each Const class Element in the con array, the Const class initialization will be triggered, as shown below:
Class Const {static {System. out. println (initialize the Const class);} public class ArrayTest {public static void main (String [] args) {Const [] con = new Const [5]; for (Const: con) a = new Const ();}}
The following output result is displayed:
Initialize the Const class
According to the first of the four rules, the new class starts the Const class.
Finally, let's take a look at the differences between the interface initialization process and the class initialization process.
The interface also has an initialization process. In the above Code, we use static statement blocks to output initialization information, but the "static {}" Statement block cannot be used in the interface, but the compiler will still generate Class constructor, used to initialize the member variables defined in the interface.
The main difference between the two during initialization is: when a class is initialized, it is required that all its parent classes have been initialized, but when an interface is initialized, the parent interface is not required to complete initialization. The parent interface is initialized only when the parent interface is actually used (for example, a constant defined in the reference interface.