Interview question: class loading process, which class loaders are available in the parent delegation model!=!= I haven't seen the Java class loading process

Java class loading process

 
The whole life cycle includes seven stages: loading, verification, preparation, parsing, initialization, use and unloading.

The class loading process includes five stages: loading, verification, preparation, parsing and initialization.

The task of the class loader is to read the binary byte stream of a class into the JVM according to the fully qualified name of the class, and then convert it into a java.lang.Class object instance corresponding to the target class.
BootstrapClassLoader、ExtClassLoader和AppClassLoader
The defineClass method converts the byte array of the bytecode into a class object instance of a class. If you want the class to be linked when it is recorded in the JVM, you can call the resolveClass method.

 

The custom class loader needs to inherit the abstract class ClassLoader and implement the findClass method, which will be called when loadClass is called, and findClass will throw an exception by default.

The findClass method means to find a class object according to the class name
The loadClass method indicates that the parent delegate model is loaded according to the class name and the class object is returned
The defineClass method means that the bytecode of the class is converted into a class object

 

The parent delegation model, the loading mechanism of the agreed class loader

copy code
When a class loader receives a class loading task, it will not expand the loading immediately, but delegate the loading task to its parent class loader for execution. until the top-level startup class loader. If the parent class loader cannot load the class delegated to it, the class loading task is returned to the next-level class loader to perform the loading.

The working process of the parent delegation model is as follows: 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 class loader to complete, and each level of class The same is true for loaders, so all load requests should eventually be sent to the top-level startup class loader, only when the parent class loader reports that it cannot complete the load request (the class that needs to be loaded is not found in its search scope). ), the subloader will try to load it by itself.
The advantage of using the parent delegation mechanism is that it can effectively ensure the global uniqueness of a class. When there are multiple classes with the same qualified name in the program, the class loader will always only load one of the classes when performing loading.

An obvious benefit of using the parent delegation model to organize the relationship between class loaders is that a Java class has a prioritized hierarchy with its class loaders. For example, the class java.lang.Object is stored in rt.jar. No matter which class loader wants to load this class, it is ultimately delegated to the startup class loader at the top of the model for loading. Therefore, the Object class is loaded in the program. is the same class in the various loader environments of . On the contrary, if the parent delegation model is not used, and each class loader loads it by itself, if the user writes a class called java.lang.Object and puts it in the ClassPath of the program, there will be many problems in the system. A different Object class, the most basic behavior in the Java type system is not guaranteed, and the application will become chaotic. If you write a Java class with the same name as an existing class in the rt.jar class library, you will find that it can be compiled normally, but it will never be loaded and run.


The parent delegation model is very important to ensure the stable operation of Java programs, but its implementation is very simple. The code for implementing parent delegation is concentrated in the loadClass() method of java.lang.ClassLoader. The logic is clear and easy to understand: first check whether the If it has been loaded, if it is not loaded, the loadClass() method of the parent class loader will be called. If the parent loader is empty, the startup class loader will be used as the parent loader by default. If the parent class loader fails to load, after throwing a ClassNotFoundException exception, call its own findClass method to load it.
copy code

 

 

copy code
1. Load
Simply put, the class loading stage is that the class loader is responsible for reading the binary byte stream of a class to the inside of the JVM according to the fully qualified name of a class, and storing it in the method area of ​​the runtime memory area, and then converting it to An instance of a java.lang.Class object corresponding to the target type (the Java virtual machine specification does not explicitly require that it must be stored in the heap area, but hotspot chooses to store the class in the method area). This Class object will be stored in the method area in the future. It will be used as the access entry for various data of the class in the method area.
2. Links
What the linking stage does is to merge the class data information of the binary byte stream loaded into the JVM into the runtime state of the JVM, through three stages of verification, preparation and parsing.
1), verify
Verify whether the class data information conforms to the JVM specification and whether it is a valid bytecode file. The verification content covers the format verification, semantic analysis, and operation verification of the class data information.
Format validation: Validate compliance with the class file specification
Semantic verification: check whether a type marked as final contains subclasses; check that final methods in a class are overridden by subclasses; ensure that there are no incompatible method declarations between parent and subclasses (such as the same method signature) , but the return value of the method is different)
Operation verification: The data in the operand stack must be correctly manipulated, and verification is performed on various symbolic references in the constant pool (usually performed in the parsing phase, checking whether the fully qualified name described in the rich reference is located on the specified type , and whether the access modifier of the class member information allows access, etc.)
copy code

 

 

copy code
2), prepare
Allocate memory space for all static variables in the class, and set an initial value for it (because the object has not yet been generated, the instance variable is not within the scope of this operation) 
The static variable modified by final will be directly assigned the original value; the field of the class field If there is a ConstantValue property in the property table, then in the preparation stage, its value is the value of ConstantValue 3), analysis Convert the symbolic reference in the constant pool to a direct reference (get the pointer or offset of the class or field, method in memory, so that the method can be called directly), which can be executed after initialization.
It can be considered that some static bindings will be parsed, and dynamic bindings will only be parsed at runtime; static bindings include some final methods (cannot be overridden), static methods (only belong to the current class), constructors (will not be rewritten) 3. Initialization Execute all the code identified by the static keyword in a class uniformly. If the static variable is executed, the initial value set in the preparation phase will be overwritten with the value specified by the user; if the static code block is executed, then During the initialization phase, the JVM executes all operations defined in the static code block. All class variable initialization statements and static code blocks will be placed in the collector by the front-end compiler at compile time, and stored in a special method. This method is the <clinit> method, that is, the class/interface initialization method. The function of this method is to initialize the variables in one, and use the user-specified value to overwrite the initial value set in the preparation phase. The <clinit> method cannot be called by any bytecode like invoke, because this method can only be called by the JVM during class loading. If the parent class has not been initialized, the parent class will be initialized first, but the <clinit> method of the parent class will not be called explicitly inside the <clinit> method. The JVM is responsible for ensuring that before the <clinit> method of a class is executed, its The parent class <clinit> method has been executed. The JVM must ensure that a class is initialized during the initialization process. If multiple threads need to initialize it at the same time, only one thread can be allowed to initialize it, and the other threads must wait, only after the active thread has completed the initialization of the class. , other threads that are waiting will be notified.
The whole life cycle includes seven stages: loading, verification, preparation, parsing, initialization, use and unloading.

The class loading process includes five stages: loading, verification, preparation, parsing and initialization.

The task of the class loader is to read the binary byte stream of a class into the JVM according to the fully qualified name of the class, and then convert it into a java.lang.Class object instance corresponding to the target class.
BootstrapClassLoader、ExtClassLoader和AppClassLoader
The defineClass method converts the byte array of the bytecode into a class object instance of a class. If you want the class to be linked when it is recorded in the JVM, you can call the resolveClass method.

 

The custom class loader needs to inherit the abstract class ClassLoader and implement the findClass method, which will be called when loadClass is called, and findClass will throw an exception by default.

The findClass method means to find a class object according to the class name
The loadClass method indicates that the parent delegate model is loaded according to the class name and the class object is returned
The defineClass method means that the bytecode of the class is converted into a class object

 

The parent delegation model, the loading mechanism of the agreed class loader

copy code
When a class loader receives a class loading task, it will not expand the loading immediately, but delegate the loading task to its parent class loader for execution. until the top-level startup class loader. If the parent class loader cannot load the class delegated to it, the class loading task is returned to the next-level class loader to perform the loading.

The working process of the parent delegation model is as follows: 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 class loader to complete, and each level of class The same is true for loaders, so all load requests should eventually be sent to the top-level startup class loader, only when the parent class loader reports that it cannot complete the load request (the class that needs to be loaded is not found in its search scope). ), the subloader will try to load it by itself.
The advantage of using the parent delegation mechanism is that it can effectively ensure the global uniqueness of a class. When there are multiple classes with the same qualified name in the program, the class loader will always only load one of the classes when performing loading.

An obvious benefit of using the parent delegation model to organize the relationship between class loaders is that a Java class has a prioritized hierarchy with its class loaders. For example, the class java.lang.Object is stored in rt.jar. No matter which class loader wants to load this class, it is ultimately delegated to the startup class loader at the top of the model for loading. Therefore, the Object class is loaded in the program. is the same class in the various loader environments of . On the contrary, if the parent delegation model is not used, and each class loader loads it by itself, if the user writes a class called java.lang.Object and puts it in the ClassPath of the program, there will be many problems in the system. A different Object class, the most basic behavior in the Java type system is not guaranteed, and the application will become chaotic. If you write a Java class with the same name as an existing class in the rt.jar class library, you will find that it can be compiled normally, but it will never be loaded and run.


The parent delegation model is very important to ensure the stable operation of Java programs, but its implementation is very simple. The code for implementing parent delegation is concentrated in the loadClass() method of java.lang.ClassLoader. The logic is clear and easy to understand: first check whether the If it has been loaded, if it is not loaded, the loadClass() method of the parent class loader will be called. If the parent loader is empty, the startup class loader will be used as the parent loader by default. If the parent class loader fails to load, after throwing a ClassNotFoundException exception, call its own findClass method to load it.
copy code

 

 

copy code
1. Load
Simply put, the class loading stage is that the class loader is responsible for reading the binary byte stream of a class to the inside of the JVM according to the fully qualified name of a class, and storing it in the method area of ​​the runtime memory area, and then converting it to An instance of a java.lang.Class object corresponding to the target type (the Java virtual machine specification does not explicitly require that it must be stored in the heap area, but hotspot chooses to store the class in the method area). This Class object will be stored in the method area in the future. It will be used as the access entry for various data of the class in the method area.
2. Links
What the linking stage does is to merge the class data information of the binary byte stream loaded into the JVM into the runtime state of the JVM, through three stages of verification, preparation and parsing.
1), verify
Verify whether the class data information conforms to the JVM specification and whether it is a valid bytecode file. The verification content covers the format verification, semantic analysis, and operation verification of the class data information.
Format validation: Validate compliance with the class file specification
Semantic verification: check whether a type marked as final contains subclasses; check that final methods in a class are overridden by subclasses; ensure that there are no incompatible method declarations between parent and subclasses (such as the same method signature) , but the return value of the method is different)
Operation verification: The data in the operand stack must be correctly manipulated, and verification is performed on various symbolic references in the constant pool (usually performed in the parsing phase, checking whether the fully qualified name described in the rich reference is located on the specified type , and whether the access modifier of the class member information allows access, etc.)
copy code

 

 

copy code
2), prepare
Allocate memory space for all static variables in the class, and set an initial value for it (because the object has not yet been generated, the instance variable is not within the scope of this operation) 
The static variable modified by final will be directly assigned the original value; the field of the class field If there is a ConstantValue property in the property table, then in the preparation stage, its value is the value of ConstantValue 3), analysis Convert the symbolic reference in the constant pool to a direct reference (get the pointer or offset of the class or field, method in memory, so that the method can be called directly), which can be executed after initialization.
It can be considered that some static bindings will be parsed, and dynamic bindings will only be parsed at runtime; static bindings include some final methods (cannot be overridden), static methods (only belong to the current class), constructors (will not be rewritten) 3. Initialization Execute all the code identified by the static keyword in a class uniformly. If the static variable is executed, the initial value set in the preparation phase will be overwritten with the value specified by the user; if the static code block is executed, then During the initialization phase, the JVM executes all operations defined in the static code block. All class variable initialization statements and static code blocks will be placed in the collector by the front-end compiler at compile time, and stored in a special method. This method is the <clinit> method, that is, the class/interface initialization method. The function of this method is to initialize the variables in one, and use the user-specified value to overwrite the initial value set in the preparation phase. The <clinit> method cannot be called by any bytecode like invoke, because this method can only be called by the JVM during class loading. If the parent class has not been initialized, the parent class will be initialized first, but the <clinit> method of the parent class will not be called explicitly inside the <clinit> method. The JVM is responsible for ensuring that before the <clinit> method of a class is executed, its The parent class <clinit> method has been executed. The JVM must ensure that a class is initialized during the initialization process. If multiple threads need to initialize it at the same time, only one thread can be allowed to initialize it, and the other threads must wait, only after the active thread has completed the initialization of the class. , other threads that are waiting will be notified.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325525444&siteId=291194637