The order of Java class initialization is often confusing, and now this article tries to give the JVM an explanation by experimenting with the initialization order of classes in the Java non-inheritance and inheritance relationships from the JVM's point of view. initialization order in a non-inheritance relationship
For non-inheritance relationships, the main class initialorderwithoutextend contains an instance of the static member variable (class variable) SampleClass class, the normal member variable SampleClass The 2 instances of the class (in different order in the program), and a static code block in which the static member variable Sam is not empty, changes the Sam's reference. The main () method creates 2 main class objects that print the properties s of the static member Sam of the 2 main class objects.
Code 1:
Package com.j2se;
public class Initialorderwithoutextend {static SampleClass Sam = new SampleClass ("Static member Sam initialization");
SampleClass sam1 = new SampleClass ("Normal member sam1 initialization");
static {System.out.println ("Static Block Execution");
if (Sam = = null) System.out.println ("Sam is null");
Sam = new SampleClass ("Initialize SAM member variable in static block");
} sampleclass sam2 = new SampleClass ("Normal member sam2 initialization");
Initialorderwithoutextend () {System.out.println ("initialorderwithoutextend default constructor called");
public static void Main (string[] args) {//Create 1th Main class object System.out.println ("1th Main class object:");
Initialorderwithoutextend ts = new Initialorderwithoutextend ();
Create a 2nd Main class object System.out.println ("2nd Main class object:");
Initialorderwithoutextend ts2 = new Initialorderwithoutextend ();
View static members of two main class objects: System.out.println ("Static objects for 2 main class objects:");
SYSTEM.OUT.PRINTLN ("1th main class object, static member Sam.s:" + Ts.sam); SYSTEM.OUT.PRINTLN ("2nd main class object, Static member Sam.s: "+ Ts2.sam); Class SampleClass {//SampleClass cannot contain any of the main class Initialorderwithoutextend member variables//Otherwise cause circular references, cyclic initialization, call stack depth too large//throw
StackOverflow exception//static initialorderwithoutextend IniClass1 = new Initialorderwithoutextend ("Static member IniClass1 initialization");
Initialorderwithoutextend iniClass2 = new Initialorderwithoutextend ("normal member member INICLASS2 initialization");
String s;
SampleClass (String s) {this.s = s;
System.out.println (s);
} sampleclass () {System.out.println ("SampleClass default constructor called");
@Override public String toString () {return this.s; }
}
Output results:
Static member Sam initialization static
block
initialize SAM member variable in static block
1th Main class object:
Normal member sam1 initialize
normal member sam2 initialization
The Initialorderwithoutextend default constructor is invoked to the
2nd main class object:
Normal member sam1 initialize
normal member sam2 initialization
The Initialorderwithoutextend default constructor is invoked
for static objects of 2 main class objects: The
1th Main class object, the static member Sam.s: Initializes the SAM member variable
2nd main class object in the static block, Static member SAM.S: initializing SAM member variables within a static block
From the results of the output, the order of execution is as follows: static static code block and statically member normal member constructor execution
When you have more than one static member and a static code block or multiple ordinary members, the initialization order is the same as the order in which the members are declared in the program.
Note that a reference to a static member Sam is modified in the static code block of the program. 2 main class objects were created in the main () method, but the output shows that static members and static code blocks are initialized only once, and that the static member SAM.S of the newly created 2 main class objects are the same. As it is, static members of classes and static blocks of code are initialized first in class loading and only once. Multiple instances of the class share static members, and references to static members point to references given at the end of the program. initialization order in an inheritance relationship
3 classes are used here to validate the initialization order in the inheritance relationship: Father parent, son subclass, and sample class. The parent class and subclass contain a non-static code area, a static code area, a static member, and an ordinary member. The main class at run time is the Initialorderwithextend class, the object of a subclass is created in the main () method, and a reference to the Son class instance is used with the Father object (the parent object points to the subclass reference, polymorphism).
Code 2:
Package com.j2se;
public class Initialorderwithextend {public static void main (string[] args) {Father ts = new Son ();
The class Father {{System.out.println ("Parent class is not static block 1 execution");
static {System.out.println ("parent class static block 1 execution");
static Sample staticSam1 = new sample ("Parent static member STATICSAM1 initialization");
Sample sam1 = new sample ("Parent normal member SAM1 initialization");
static Sample staticSam2 = new sample ("Parent static member StaticSam2 initialization");
static {System.out.println ("parent class static block 2 Execution");
} Father () {System.out.println ("parent class default constructor called");
Sample sam2 = new sample ("Parent normal member SAM2 initialization");
{SYSTEM.OUT.PRINTLN ("Parent class is not static block 2 execution");
Class Son extends Father {{System.out.println ("subclass non-static block 1 execution");
static Sample staticSamSub1 = new sample ("Subclass static member StaticSamSub1 initialization");
Son () {System.out.println ("subclass default constructor called");
Sample sam1 = new sample ("Subclass normal member sam1 initialization"); StaticSample STATICSAMSUB2 = new sample ("Subclass static member StaticSamSub2 initialization");
static {System.out.println ("Subclass static block 1 execution");
Sample sam2 = new sample ("Subclass normal member Sam2 initialization");
{System.out.println ("subclass non static Block 2 execution");
static {System.out.println ("Subclass static Block 2 execution");
Class Sample {sample (String s) {System.out.println (s);
Sample () {System.out.println ("the default constructor for the sample is invoked"); }
}
Run Result:
The parent class static Block 1 executes the parent class statically member STATICSAM1 initializes the parent class
static member StaticSam2 initializes the
parent class static Block 2 executes the
subclass statically member Staticsamsub 1 initialization
Subclass static member StaticSamSub2 initialization subclass static block
1 execute
subclass static Block 2 Execute
parent class Non-static block 1 execute
normal member of parent class SAM1 Initialize parent class
normal member Sam2 initialize
parent class Non-static block 2 Execute
Parent class default constructor is called
subclass non-static Block 1 execute
subclass Normal member sam1 initialize
Subclass Normal member Sam2 initialization
subclass non-static Block 2 execution
subclass default constructor is called
The order of execution is as follows: The parent class static code area and the static member subclass of the parent class static code region and the subclass static member parent class non-static code region and ordinary member parent class constructor subclass non-static code region and ordinary member subclass constructor
The same place as the initialization order in a non-inheritance relationship is that the static code area and the parent class static members, Non-static code extents, and ordinary members are the same level, and when multiple such blocks or members are present, the order of initialization is the same as the order in which they are declared in the program; Static code extents and static members are initialized only once, but in the initialization process, you can modify the references of static members. diagram of initialization order
non-inheritance relationship
Inheritance Relationship
JVM Interpretation of class initialization order
Class initialization order is controlled by the JVM class loading mechanism, including loading, verification, preparation, parsing, initialization and so on. The initialization order of a class is primarily influenced by the JVM class load timing, parsing, and Clinit () initialization rules, whether in inheritance or in a non-inheritance relationship. Loading Time
loading is the first phase of the class loading mechanism, which triggers the loading of the class only in the case of 5 active references , and does not trigger the loading of the class in the case of other passive references. For more information about class loading timing and active and passive references in 5, see "Deep Understanding JVM": Class loading mechanism. Of these, 3 types of active references are: When a program starts to trigger the main method, the virtual opportunity triggers the initialization of the class to instantiate the object with the new keyword, to read or set a static field of a class (except for static fields that are final decorated with a constant pool when JIT is placed), and to invoke a static method of a class Triggers initialization when a class is initialized, if its parent class is not initialized, the initialization of its parent class needs to be triggered first
Before triggering the main () method in code 1, you need to trigger initialization of the main class initialorderwithoutextend, after initialization of the main class, and after initializing the static code area and static member, print the "1th Main class object:", Then the newinitialorderwithoutextend ts = new Initialorderwithoutextend () is encountered, and other normal variables are initialized.
Code 2 is an inheritance relationship that must first trigger the initialization of the parent class before the subclass initializes. The bottom-up recursion of class parsing in inheritance relations
The parsing phase of the class loading mechanism replaces the symbolic reference in the constant pool with a direct reference, mainly for classes or interfaces, fields, class methods, method types, method handles, and call point qualifier 7 notation references. The parsing process for classes is detailed in "deep Understanding JVM": Class loading mechanism.
In field parsing, class method parsing, in the method type parsing, we follow the rule of the bottom-up recursive search parsing in the inheritance relation, because the recursive characteristic (i.e. the "LIFO" of the stack in the data structure), the initialization process is from the top down, from the parent class to the subclass of the initialization order. Initialize the Clinit () method
The initialization phase is the process of executing the Class builder method Clinit (). Clinit () is a collection of assignment actions and Static statement blocks merged by the compiler to automatically collect all class variables (static variables) in a class. The order that the compiler collects is determined by the order in which the statements appear in the source file. The JVM guarantees that the Clinit () method of the parent class has been executed before the Clinit () method of the subclass is executed.
Therefore, all initialization processes are clinit () to ensure that static variables and static statement blocks are always initialized first, and must be performed first by the parent class Clinit (), in the execution subclass of the Clinit (). Code Order and object memory layout
In the previous analysis, we saw that the initialization of the class had a relatively fixed order: the static code area and the static variable precede the Non-static code area and the normal member before the constructor. During the initialization of the same level, the initialization order is consistent with the variable definition in the order of the program.
The code order is also affected in the object memory layout. (For the JVM object memory layout, see "Deep Understanding JVM": Java object creation, memory layout, access positioning.) )
In a hotspot virtual machine, the layout in which objects are stored in memory can be divided into 3 areas: Object Headers (header), instance data (Instance), and alignment padding (Padding). The instance data is the valid information that the object is actually stored, and it is also the various types of field content defined in the program code.
The
, whether inherited from the parent class or defined by a subclass, needs to be logged, which is the effect of the order in which the JVM parameters and fields are defined in the program source code. Hotspot virtual Machine The default allocation policy is Longs/doubles, INTs, Shorts/chars, Bytes/booleans, OOP, as you can see from the allocation policy that fields of the same width are always assigned together. If this condition is met, the variables defined in the parent class appear before the subclass. However, if JVM parameter Compactfields (default is True, enabled) is enabled, the narrower variable in the subclass may also be inserted into the void of the parent class variable.