This article brings you a detailed introduction (code example) about the JVM class loading mechanism. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
Java is different from traditional compiled languages such as C/C, and also different from dynamic scripting languages such as PHP. It can be said that Java is a semi-compiled language. The class we write will first be compiled into a .class file. This .class is a binary byte stream. Then when this class is used, the .class file corresponding to this class will be loaded into memory. The content of this .class is loaded into memory through the Jvm class loading mechanism.
The virtual machine loads the data describing the class from the class file into the memory, verifies the data, converts, parses and initializes it, and finally forms a Java type that can be used directly by the virtual machine. This is the class of the virtual machine. loading mechanism.
Loading
The first step in the "class loading" process when loading, During the loading process, the virtual machine needs to complete the following three things
Get the binary byte stream that defines this class through the fully qualified name of a class.
Convert the static storage structure represented by this byte stream into the runtime data structure of the method area.
Generate a java.lang.Class object representing this class in the memory, which serves as the access entry for various data of this class in the method area.
It is worth mentioning that the loading phase can be completed using the boot class loader provided by the system or by a user-defined class loader. It is relatively free, but this is not the case for arrays. The array class itself is not created through class loading, it is created directly by the Java virtual machine. But the element type where the data is stored needs to be created by the class loader.
The loading phase and the connection part of the next phase are interleaved, but the start time of the loading phase and the connection phase will still maintain a fixed sequence.
Verification
Verification is the first step in the connection phase. The purpose of this phase is to ensure that the information contained in the byte stream of the Class file is combined with the current virtual machine requirements and will not endanger the security of the virtual machine itself. Although operations such as array out-of-bounds and random transformation of objects will be rejected by the compiler, the .class file does not necessarily need to be compiled from Java source code and can be generated from other ways. Therefore, the binary stream of the .class file needs to be verified. .
The importance of the verification phase is self-evident. Whether this stage is rigorous or not directly determines whether the Java virtual machine can withstand malicious code attacks. From the perspective of execution performance, the work of the verification phase The load accounts for a considerable part of the class loading system of the virtual machine.
Overall, the verification phase can be roughly divided into 4 parts of verification actions: file format verification, metadata verification, bytecode verification, and symbol reference verification.
Symbol verification: The main purpose is to ensure that the input byte stream can be correctly parsed and stored in the method area, and that the format meets the requirements for describing a Java type information. This part is based on binary stream verification, which will then be loaded into memory, and subsequent verification is performed in memory.
Metadata verification: This verification mainly performs semantic verification on the metadata information of the class to ensure that there is no metadata information that does not comply with the Java language specification.
Bytecode verification: This part is the most complex stage of the verification stage. The main purpose is to determine that the program is legal and logical through data flow and control flow analysis.
Symbol reference verification: Symbol reference occurs when the virtual machine converts the symbol reference into a direct reference, so that the parsing action can be executed normally.
Preparation
The preparation phase is the phase where memory is allocated for formal class variables (static variables) and the initial values of the class variables are set. The memory used is allocated in the method area. It is worth mentioning that only class variables (static variables) are allocated at this time, not instance variables.
Normally, set the initial value of a class variable. This initial value refers to the default value of the data type, such as 0 for int type. But if the class variable is modified by final, the situation is different. In that case, the given value will be assigned directly.
Parsing
The parsing phase is the process in which the virtual machine replaces symbol references in the constant pool with direct references. Here is an explanation of what is a symbolic reference and what is a direct reference.
Symbolic reference: A symbolic reference uses a set of symbols to describe the referenced target. The symbol can be any form of literal, as long as the target can be located unambiguously when used.
Direct reference: A direct reference can be a pointer to the target, a relative offset or a handle that can indirectly locate the target.
The parsing action is mainly performed on seven types of symbol references: classes or interfaces, fields, class methods, interface methods, method types, method handles and call site qualifiers.
initialization
The class initialization phase is the last step of the class loading process. In the previous class loading process, except that user applications can participate through a custom class loader during the loading phase, the remaining actions are completely dominated and controlled by the virtual machine. In the initialization phase, the Java code defined in the class will actually start to be executed.
In the preparation phase, the variables have been assigned the initial value required by the system, and in the initialization phase, class variables and other resources are initialized according to the plan area made by the programmer through the program.
public class StaticTest { public static void main(String[] args) { staticFunction(); } static StaticTest st = new StaticTest(); static { System.out.println("1"); } { System.out.println("2"); } StaticTest() { System.out.println("3"); System.out.println("a="+a+",b="+b); } public static void staticFunction(){ System.out.println("4"); } int a=110; static int b =112; }
What is the result of this code?
The answer is:
2 3 a=110,b=0 1 4
Why is this? You may wish to think about the following.
Understanding this code requires not only understanding Java's class loading mechanism, but also the initialization phase. The initialization sequence of static code blocks and static member variables is related to the code sequence.
The process of class loading is: loading->connection (verification, preparation, parsing)->initialization.
1. In the preparation phase, the default value will be set for the class variable, so in case one: st=null, b=0,
2. In the initialization phase, the class will be executed first Constructor,
In other words, it just executes the static-modified code block and assigns values to the static-modified variables. The execution order of static-modified code blocks and class variables is based on the order in which they appear in the file. And static StaticTest st = new StaticTest() is ranked first, so new StaticTest() will be executed, that is, the object is initialized
2.1. During the initialization process of the object, the member variables (code block), and then execute the constructor method. The execution order of member variables is also whoever declares it first will execute it first, so the code block ranked first
2.2 After the member variable is executed, the constructor method is executed. At this time ,a=110,b=0;
3. The initialization process of non-static code triggered by static StaticTest st = new StaticTest(); ends here, and then the initialization of static code continues, so the output 1 .
4. The entire class loading ends here, the code is executed, and 4 is output.
Look at the next one
public class StaticTest { public static void main(String[] args) { staticFunction(); } static { System.out.println("1"); } { System.out.println("2"); } StaticTest() { System.out.println("3"); System.out.println("a="+a+",b="+b); } public static void staticFunction(){ System.out.println("4"); } int a=110; static int b =112; static StaticTest st = new StaticTest(); //将这条语句放到最下面 }
Just change one statement, and the running result of this code is
1 2 3 a=110,b=112 4
The above is the detailed content of Detailed introduction to JVM class loading mechanism (code example). For more information, please follow other related articles on the PHP Chinese website!