JVM class loading mechanism
class life cycle
Load - Verify - Prepare - Parse - Initialize - Use - Unload
Among them: loading, verification, preparation, initialization, and unloading are strictly ordered
Class loading timing:
The class loading time here refers to the time when the class enters the life cycle, not the first stage of loading.
Active loading of a class occurs actively if and only if five conditions are met:
1. Encounter new, getstatic, putstatic, invokestatic bytecode (for special cases, see the verification below)
2. Called by reflection
3. When the subclass is initialized, its parent class will be actively loaded
4. The main class with the main method will be loaded at startup
5. In some cases using dynamic language support
In addition, the method of the referenced class will not be loaded by the class
This can be verified by the fact that the static initializer block is always called when the class is initialized during class loading.
Three classes are defined here to illustrate the validation part:
public class Test { //public final static int SIZE = 1; publicstaticintSIZE = 1; // static initializer block will be called when the class is initialized static{ System.out.println("test init"); } } public class Test2 extends Test{ static { System.out.println("test2 init"); } } /** * The three-line verification in the main method needs to comment out one or two lines in more cases * * @author shiin * */ public class Test3 { publicstaticvoid main(String[] args) { //Call the static variable SIZE directly through Test, the Test class that defines the static variable will be initialized intsize = Test.SIZE; //Call the static variable SIZE through the Test subclass Test2. The Test class that defines the static variable will be initialized and its subclasses will not be initialized //Once the SIZE here is modified by final, SIZE becomes a static constant that enters the constant pool at compile time. At this time, neither Test nor Test2 can lead to the initialization of the class intsize1 = Test2.SIZE; //Defining an array of classes does not cause the class to be initialized Test2[] t2 = new Test2[5]; } }
Class loading process:
load:
1. Get the binary byte stream of the class through the full name of the class
2. Obtain its data structure through the binary byte stream and write it into the method area
3. Generate a class object of this class in memory as the entry for various data accesses
verify:
Consider using the virtual machine parameter -Xverify:none to turn off most verification measures under the premise of being sure that the code is correct
1. File format verification
2. Element data verification
3. Bytecode Verification
4. Symbolic reference verification
Prepare:
1. Allocate memory for static class variables
2. Set the initial value of the static class variable to the zero value of the corresponding type
Note: Final static modified class static constants (limited to types with ConstantValue properties) will be assigned initial values instead of zero values during the preparation phase
Parse:
Replace symbolic references within the constant pool with direct references
This process includes analysis of various classes (interfaces), methods (interface methods and class methods), and fields
initialization:
This phase will execute the class constructor <clinit()> method
<clinit()> a method composed of all class variable assignment actions and static code blocks
The execution order in this method is determined by the order of appearance in the source file, so the static code block that appears first cannot access the class variables defined later, but the variables that appear later can be defined in the static code block that appears first. For example Say:
public class Test { public static void main(String[] args) { } static { SIZE = 0; } public static int SIZE ; static{ System.out.println(SIZE); } }
This program will output 0 in the console, but if you try to add System.out .println ( SIZE ) in the first static code block , the program will report an error , prompting Cannot reference a field before it is defined , which means that it cannot be defined before reference the variable
The virtual machine ensures that the <clinit()> method of the parent class is executed before the subclass <clinit()>, and the instance constructor <init>() of the class must be executed after the <clinit()> method of the class
The class constructor <clinit()> method is not necessarily generated. When there is no member variable assignment operation and static code block, this method may not be generated.
There cannot be static code blocks in the interface, but member variables can be assigned values, and the class constructor <clinit()> method of the interface will execute the <clinit()> method of the interface only when the class that implements the interface uses the variables in the interface ()> method
When multiple threads call the <clinit()> method of the same class, the <clinit()> method will be locked and synchronized, and the same <clinit()> method will only be executed once. The <clinit()> method will not be called