Please indicate the source for reprint: http://blog.csdn.net/ns_code/article/details/17881581
class loading process
The entire life cycle of a class starts from being loaded into the virtual machine memory and unloads the memory, and its entire life cycle includes seven stages: loading, verification, preparation, parsing, initialization, use, and unloading. The order in which they start is shown in the following diagram:
The class loading process includes five stages: loading, verification, preparation, parsing, and initialization. Among the five phases, the order in which the four phases of loading, verification, preparation and initialization occur is determined, while the parsing phase is not necessarily, it can start after the initialization phase in some cases, this is to support Java Runtime binding of the language (also known as dynamic binding or late binding). Also note that the phases here are started sequentially, not performed or completed sequentially, as these phases are usually intermixed with each other, usually invoking or activating one phase while another is being executed.
Here is a brief description of binding in Java: binding refers to associating the invocation of a method with the class (method body) where the method is located. For java, binding is divided into static binding and dynamic binding:
- Static binding: that is, early binding. The method has been bound before the program is executed, and it is implemented by the compiler or other linker at this time. For java, it can be simply understood as the binding at the compile time of the program. Only methods in java are final, static, private and constructors are early bound.
- Dynamic binding: that is, late binding, also known as runtime binding. Binding at runtime is based on the type of the concrete object. In java, almost all methods are late bound.
load
The first stage of the class loading process at load time, during the loading stage, the virtual machine needs to do three things:
1. Obtain the binary byte stream defined by the fully qualified name of a class.
2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area.
3. Generate a java.lang.Class object representing this class in the Java heap as the access entry to the data in the method area.
Note that the binary byte stream in item 1 here is not simply obtained from the Class file. For example, it can also be obtained from the Jar package, obtained from the network (the most typical application is Applet), and other files. Generation (JSP application) and so on.
Compared with other stages of class loading, the loading stage (to be precise, the action of obtaining the binary byte stream of the class in the loading stage) is the most controllable stage, because developers can use the class loading provided by the system. You can use the class loader to complete the loading, or you can customize your own class loader to complete the loading.
After the loading phase is completed, the binary byte stream outside the virtual machine is stored in the method area according to the format required by the virtual machine, and an object of the java.lang.Class class is also created in the Java heap, so that the Objects access these data in the method area.
When it comes to loading, we have to mention the class loader, and the class loader will be described in detail below.
Although the class loader is only used to implement class loading, its role in Java programs is far from limited to the class loading phase. For any class, its class loader and the class itself need to determine its uniqueness in the Java virtual machine, that is, even if two classes come from the same Class file, as long as their classes are loaded If the loader is different, the two classes must not be equal. The "equal" here includes the return results of the equals(), isAssignableFrom(), isInstance() and other methods of the Class object representing the class, and also includes the judgment result of the object ownership using the instanceof keyword.
From the perspective of the Java virtual machine, there are only two different class loaders:
- Startup class loader: It is implemented in C++ (this is limited to Hotspot, which is the default virtual machine after JDK1.5, there are many other virtual machines implemented in Java language), which is a part of the virtual machine itself.
- All other class loaders: These class loaders are implemented by the Java language, independent of the virtual machine, and all inherit from the abstract class java.lang.ClassLoader, these class loaders need to be loaded into memory by the startup class loader Only then can other classes be loaded.
From a Java developer's point of view, class loaders can be roughly divided into the following three categories:
- Bootstrap ClassLoader: Bootstrap ClassLoader, same as above. It is responsible for loading the class library stored in JDK\jre\lib (JDK represents the installation directory of JDK, the same below), or in the path specified by the -Xbootclasspath parameter, and can be recognized by the virtual machine (such as rt.jar, all The classes starting with java.* are loaded by Bootstrap ClassLoader). The startup class loader cannot be directly referenced by a Java program.
- Extension class loader: Extension ClassLoader, which is implemented by sun.misc.Launcher$ExtClassLoader, which is responsible for loading all classes in the JDK\jre\lib\ext directory or the path specified by the java.ext.dirs system variable Libraries (such as classes starting with javax.*), developers can directly use the extension class loader.
- Application class loader: Application ClassLoader, this class loader is implemented by sun.misc.Launcher$AppClassLoader, which is responsible for loading the classes specified by the user class path (ClassPath), developers can use this class loader directly, if the application The program has not customized its own class loader. In general, this is the default class loader in the program.
The application is loaded by the cooperation of these three class loaders. If necessary, we can also add custom class loaders. Because the ClassLoader that comes with the JVM only knows how to load standard java class files from the local file system, if you write your own ClassLoader, you can do the following:
1) Automatically verify digital signatures before executing untrusted code.
2) Dynamically create custom build classes that meet user-specific needs.
3) Get the java class from a specific place, such as the database and the network.
In fact, when using Applet, a specific ClassLoader is used, because at this time it is necessary to load java classes from the network, and to check the relevant security information, and most of the application servers also use the custom ClassLoader technology.
The hierarchical relationship of these class loaders is shown in the following figure:
This hierarchical relationship is called the class loader's parent delegation model. We call the class loader above each layer the parent loader of the class loader of the current layer. Of course, the parent-child relationship between them is not achieved through inheritance, but the combination relationship is used to reuse the parent loader. code. This model was introduced during JDK1.2 and was widely used in almost all Java programs after that, but it is not a mandatory constraint model, but a class loader implementation recommended by Java designers to developers .
The workflow of the parent delegation model is: if a class loader receives a class loading request, it will not try to load the class by itself first, but delegate the request to the parent loader to complete it, and so on. Therefore, all the Class loading requests should eventually be passed to the top-level startup class loader, and only if the parent loader does not find the required class in its search scope, i.e. the loading cannot be completed, the child loader will try to do it on its own. Load the class.
Using the parent delegation model to organize the relationship between class loaders has an obvious advantage, that is, a Java class has a priority with its class loader (to put it bluntly, the directory where it is located). The hierarchical relationship is very important to ensure the stable operation of Java programs. For example, the class java.lang.Object is stored in rt.jar under JDK\jre\lib, so no matter which class loader wants to load this class, it will eventually be delegated to the startup class loader for loading, which is guaranteed here The Object class is the same class in various class loaders in the program.
verify
The purpose of verification is to ensure that the information contained in the byte stream in the Class file meets the requirements of the current virtual machine, and will not endanger the security of the virtual machine itself. Different virtual machines may implement class verification differently, but they generally complete the following four stages of verification: file format verification, metadata verification, bytecode verification, and symbol reference verification.
- File format verification: Verify that the byte stream conforms to the specification of the Class file format and can be processed by the current version of the virtual machine. The main purpose of this verification is to ensure that the input byte stream can be correctly parsed and stored in the method area. . After this stage of verification, the byte stream will be stored in the method area of the memory, and the next three verifications are based on the storage structure of the method area.
- Metadata verification: Semantic verification is performed on the metadata information of the class (in fact, the syntax verification is performed on each data type in the class) to ensure that there is no metadata information that does not conform to the Java syntax specification.
- Bytecode Verification: The main work of verification at this stage is to perform data flow and control flow analysis, and to verify and analyze the method body of the class to ensure that the methods of the verified class will not do harm to the security of the virtual machine at runtime. the behavior of.
- Symbolic reference verification: This is the last stage of verification, which occurs when the virtual machine converts a symbolic reference into a direct reference (this conversion occurs in the parsing phase, which will be explained later), mainly for information other than the class itself (constant Various symbolic references in the pool) are checked for matching.
Prepare
The preparation phase is the phase in which memory is formally allocated for class variables and initial values for class variables are set, all of which will be allocated in the method area. There are a few things to note about this stage:
1. At this time, memory allocation only includes class variables (static), not instance variables. Instance variables will be allocated in the Java heap along with the object when the object is instantiated.
2. The initial value set here is usually the default zero value of the data type (such as 0, 0L, null, false, etc.), rather than the value explicitly assigned in the Java code.
Suppose a class variable is defined as:
public static int value = 3;
Then the initial value of the variable value after the preparation phase is 0, not 3, because no Java method has been executed yet, and the putstatic instruction that assigns value to 3 is stored in the class constructor <clinit> after the program is compiled. () method, so the action of assigning value to 3 will not be executed until the initialization phase.
The following table lists all the basic data types in Java and the default zero value for reference types:
Here are a few more things to note:
- For basic data types, for class variables (static) and global variables, if they are used directly without explicitly assigning them, the system will assign them a default zero value, while for local variables, before use It must be explicitly assigned, otherwise it will not pass at compile time.
- For constants that are modified by both static and final, they must be explicitly assigned when they are declared, otherwise they will not pass at compile time; while constants that are only modified by final can either be explicitly assigned at the time of declaration, or It can be explicitly assigned a value when the class is initialized. In short, it must be assigned an explicit value before use, and the system will not assign a default zero value to it.
- For the reference data type reference, such as array reference, object reference, etc., if it is used directly without explicit assignment, the system will assign it the default zero value, that is, null.
- If no value is assigned to each element in the array when the array is initialized, the elements in it will be assigned the default zero value according to the corresponding data type.
3. If the ConstantValue attribute exists in the field attribute table of the class field, that is, it is modified by both final and static, then the variable value will be initialized to the value specified by the ConstValue attribute in the preparation stage.
Suppose the above class variable value is defined as:
public static final int value = 3;
When compiling, Javac will generate the ConstantValue property for the value. During the preparation stage, the virtual machine will assign the value to 3 according to the setting of ConstantValue. This is the case, recalling the second example of passive references to objects in the previous blog post . We can understand that static final constants put their results into the constant pool of the class that calls it at compile time.
Parse
- class Super{
- public static int m = 11;
- static{
- System.out.println( "The super class static statement block was executed");
- }
- }
- class Father extends Super{
- public static int m = 33;
- static{
- System.out.println( "Executed the parent class static statement block");
- }
- }
- class Child extends Father{
- static{
- System.out.println( "Executed the subclass static statement block");
- }
- }
- public class StaticTest{
- public static void main(String[] args){
- System.out.println(Child.m);
- }
- }
Execute the super class static statement block
33
If you comment out the line defined for m in the Father class, the output is as follows:
11
both match
System.out.println(Child.m);
^
1 error
initialization
Initialization is the last step in the class loading process. At this stage, the Java program code defined in the class is actually executed. In the preparation phase, the class variables have been assigned the initial values required by the system, and in the initialization phase, the class variables and other resources are initialized according to the subjective plan specified by the programmer through the program, or it can be expressed from another angle: The initialization phase is the process of executing the class constructor <clinit>() method.- class Father{
- public static int a = 1;
- static{
- a = 2;
- }
- }
- class Child extends Father{
- public static int b = a;
- }
- public class ClinitTest{
- public static void main(String[] args){
- System.out.println(Child.b);
- }
- }
Summarize
In the whole class loading process, except that the user application can participate in the loading stage by customizing the class loader, all other actions are completely dominated and controlled by the virtual machine. The Java program code (and bytecode) defined in the class is executed only after initialization, but the execution code here is just the beginning, it is limited to the <clinit>() method. The class loading process mainly loads the Class file (accurately speaking, it should be the binary byte stream of the class) into the virtual machine memory, and the bytecode operation is actually executed, and the real start only after the loading is completed.