Class loading mechanism
Classes are loaded dynamically during the first use of the runtime, not at compile time. Because if it is loaded at compile time, it consumes a lot of memory.
Life cycle of Class 1.1
The following 7 phases are included:
- Load ( Loading )
- Verification ( Verification )
- Preparation ( Preparation )
- Parsing ( Resolution )
- Initialize ( initialization )
- Use (using)
- Uninstall (unloading)
Class 1.2 Loading process
Contains the 5 stages of loading, validating, preparing, parsing, initializing
1.2.1 Loading
Loading is a phase of class loading, so be careful not to confuse it.
The loading process completes the following three things:
- A binary byte stream that defines this class is obtained through the fully qualified name of a class.
- Converts the static storage structure represented by this byte stream into the runtime storage structure of the method area.
- Generate a class object in memory that represents this category as a access entry for various data in the method area.
Where binary byte streams can be obtained in the following ways:
- Read from the ZIP package and become the basis for the JAR, EAR, and WAR formats.
- From the network, the most typical application is the Applet.
- Run-time compute generation, such as dynamic Agent technology, uses the binary byte stream of the Proxygenerator.generateproxyclass proxy class in Java.lang.reflect.Proxy.
- Generated by other files, such as the corresponding class class generated by the JSP file.
1.2.2 Verification
Ensure that the information contained in the byte stream of the Class file conforms to the requirements of the current virtual machine and does not compromise the security of the virtual machine itself.
1.2.3 Preparation
A class variable is a static-modified variable that allocates memory for a class variable and sets an initial value, using the memory of the method area.
The instance variable does not allocate memory at this stage, it will be allocated in the heap along with the object when the object is instantiated.
Note that instantiation is not a procedure for class loading, and class loading occurs before all instantiation operations, and class loading takes place only once, and instantiation can occur multiple times.
The initial value is typically 0 values, such as the following class variable value is initialized to 0 instead of 123.
public static int value = 123;
If the class variable is a constant, it is initialized with an expression instead of an assignment of 0.
public static final int value = 123;
1.2.4 Parsing
Replace the symbolic reference of a constant pool with a direct reference procedure.
In some cases, the parsing process can begin after the initialization phase, which is to support dynamic binding of Java.
1.2.5 Initialization
The initialization phase does not really start executing the JAVA program code defined in the class. The initialization phase is the process by which the virtual machine executes the class constructor <clinit> () method.
In the preparation phase, the class variable has already assigned the initial value of the system requirement, and during the initialization phase, the class variables and other resources are initialized according to the subjective plan developed by the programmer [Chen Wenwen 1] .
The <clinit> () method has the following characteristics :
- is generated by the compiler's automatic collection of assignment actions for all class variables in a class and statements in a static statement block, the order in which the compiler collects is determined by the order in which the statements appear in the source file. It is particularly important to note that a static statement block can only access a class variable that is defined before it, and the class variable defined after it can only be assigned a value and cannot be accessed. For example, the following code:[Chen Wenwen 2]
public class Test {
static {
i = 0; Assigning values to variables can be compiled correctly
System.out.print (i); This compiler will prompt "illegal forward reference"
}
static int i = 1;
}
- Unlike constructors for classes (or instance constructors <init> ()), you do not need to explicitly call the constructor of the parent class. The virtual opportunity automatically guarantees that the parent class's <clinit> () method has finished executing before the subclass's <clinit> () method runs. [Chen Wenwen 3] therefore the first class to execute the <clinit> () method in the virtual machine is definitely java.lang.Object.
- Because the <clinit> () method of the parent class executes first, it means that the execution of the static statement block defined in the parent class takes precedence over the subclass. For example, the following code:
Static Class Parent {
public static int A = 1;
static {
A = 2;
}
}
Static Class Sub extends Parent {
public static int B = A;
}
public static void Main (string[] args) {
System.out.println (sub.b); 2
}
- The <clinit> () method is not necessary for a class or interface, and if a class does not contain a static statement block or an assignment to a class variable, the compiler can not generate the <clinit> () method for that class. [Chen Wenwen 4]
- Static statement blocks can not be used in an interface, but there are still assignment operations that initialize class variables, so the interface will generate the <clinit> () method as a class. However, unlike the class interface, the <clinit> () method of the execution interface does not require the parent interface's <clinit> () method to be executed first. The parent interface is initialized only if the variables defined in the parent interface are used. In addition, the implementation class of the interface does not execute the <clinit> () method of the interface at initialization time. [Chen Wenwen 5]
- The virtual opportunity guarantees that a class <clinit> () method is correctly locking and synchronized in a multithreaded environment, and if multiple threads initialize a class at the same time, only one thread executes the <clinit> () method of the class, and the other threads block the wait. Until the active thread executes the <clinit> () method is complete. If there is a time-consuming operation in the <clinit> () method of a class, it can cause multiple threads to block, and in practice this kind of blocking is very subtle [Chen Wenwen 6] .
Class 1.3 Initialization time 1.3.1 Active reference
The virtual machine specification does not enforce when the constraint is loaded, but the specification strictly specifies that the class must be initialized (load, validate, prepare will occur) only in the following five cases:
- When you encounter the four bytecode directives of the new, Getstatic, putstatic, Invokestatic, if the class has not been initialized, it must first trigger its initialization. The most common scenario for generating these 4 instructions is when instantiating an object using the New keyword, while reading or setting a static field of a class (except for a static field that is final decorated, which has placed the result in a constant pool at compile time), and when invoking a static method of a class.
- When you use the Java.lang.reflect package method to make a reflection call to a class, you need to trigger its initialization first if the class is not initialized.
- When initializing a class, it is necessary to trigger the initialization of its parent class if it finds that its parent class has not yet been initialized.
- When the virtual machine starts, the user needs to specify a main class to execute (the class that contains the main () method), and the virtual opportunity initializes the main class first;
- When using the dynamic language support for JDK 1.7, if a java.lang.invoke.MethodHandle instance finally resolves to ref_getstatic, ref_putstatic, the Ref_invokestatic method handle , and the class for which the method handle corresponds is not initialized, it needs to be initialized first;
1.3.2 Passive References[Chen Wenwen 7]
The behavior in the above 5 scenarios is called an active reference to a class. In addition, all methods of referencing a class do not trigger initialization, which is called a passive reference. Common examples of passive references include:
- Referencing a static field of a parent class through a subclass does not cause subclasses to initialize.
System.out.println (Subclass.value); The value field is defined in superclass
- Referencing a class through an array definition does not trigger initialization of this class. The procedure initializes the array class, which is a subclass that is automatically generated by the virtual machine and inherits directly from Object, which contains the properties and methods of the array.
superclass[] SCA = new SUPERCLASS[10];
- Constants are stored in the constant pool of the calling class at compile time and are not inherently referenced directly to the class that defines the constants, so initialization of classes that define constants is not triggered.
System.out.println (Constclass.helloworld);
Class 1.4 and Class loader
Two class equality requires that the class itself be equal and loaded with the same classloader. This is because each class loader has a separate class namespace.
The equality here, including the Equals () method of the Class object, the IsAssignableFrom () method, the Isinstance () method, return the result to true, and also includes the use of the INSTANCEOF keyword to determine the result of the object owning relationship is true.
Class 1.5 Loader categories
From the point of view of a Java virtual machine, there are only two different classloader:
- Start the ClassLoader (Bootstrap ClassLoader), a class loader implemented with C + +, which is part of the virtual machine itself;
- All other class loaders, which are implemented by Java, are independent of the virtual machine and all inherit from the abstract class Java.lang.ClassLoader.
From the Java developer's point of view, the ClassLoader can be divided in more detail:
- Launch class loader (Bootstrap ClassLoader) This loader is responsible for storing in the <jre_home>\lib directory, or in the path specified by the-xbootclasspath parameter, and is recognized by the virtual machine (only according to the name of the file, such as Rt.jar, the class library with the name does not fit even in the Lib directory will not be loaded) class library loaded into the virtual machine memory. The startup ClassLoader cannot be referenced directly by a Java program, and when a user writes a custom class loader, it needs to delegate the load request to the startup ClassLoader, using NULL instead.
- Extension class loader (Extension ClassLoader) This classloader is implemented by Extclassloader (Sun.misc.launcher$extclassloader). It is responsible for loading <java_home>/lib/ext or all class libraries in the path specified by the JAVA.EXT.DIR system variable into memory, and developers can use the extension class loader directly.
- The class loader for the application ClassLoader (application ClassLoader) is implemented by Appclassloader (Sun.misc.launcher$appclassloader). Because this classloader is the return value of the Getsystemclassloader () method in ClassLoader, it is generally referred to as the System class loader. It is responsible for loading the class library specified on the user classpath (ClassPath), which the developer can use directly, if the application does not have its own classloader, typically this is the default class loader in the program.
1.6 Parental delegation Model
The application is loaded by the three kinds of loaders, and if necessary, you can also add your own defined class loader.
The hierarchical relationship between the displayed ClassLoader, called the class loader's parental delegation model (parents delegation models). The model requires that the rest of the ClassLoader should have its own parent classloader, in addition to the top-level startup class loader. The parent-child relationship between ClassLoader is typically implemented by combining (composition) relationships, rather than by inheritance (inheritance).
1.6.1 Working process
A class loader first routes a class load request to the parent class loader and tries to load it only if the parent ClassLoader is unable to complete the class load request.
1.6.2 Benefits
Causes the Java class to have a hierarchical relationship with precedence, along with its classloader, so that the underlying classes are unified.
For example Java.lang.Object stored in Rt.jar, if you write another Java.lang.Object class and put it in ClassPath, the program can be compiled through. Because the parent delegation model exists, the object in Rt.jar is higher in object precedence than in ClassPath because object in Rt.jar uses the startup ClassLoader, and object in ClassPath uses the Use the Program class loader. The object in the Rt.jar has a higher priority, and all objects in the program are this object.
1.6.3 implementation
The following is a snippet of abstract class Java.lang.ClassLoader, where the LoadClass () method runs as follows: first check if the class has been loaded, and if not, let the parent ClassLoader load. Throws a classnotfoundexception when the parent loader fails to load, attempting to load itself.
Public Abstract classClassLoader {//The parent class loader for delegation Private FinalClassLoader Parent; PublicClass<?> loadclass (String name)throwsClassNotFoundException {returnLoadClass (Name,false); } protectedClass<?> loadclass (String name,BooleanResolvethrowsClassNotFoundException {synchronized(Getclassloadinglock (name)) {//First , check if the class has already been loadedClass<?> C =Findloadedclass (name); if(c = =NULL) { Try { if(Parent! =NULL) {C= Parent.loadclass (Name,false); } Else{C=findbootstrapclassornull (name); } } Catch(ClassNotFoundException e) {//ClassNotFoundException thrown if class not found//From the Non-null parent class loader } if(c = =NULL) { //If still not found, then invoke Findclass in order//To find the class.C=Findclass (name); } } if(Resolve) {resolveclass (c); } returnC; } } protectedClass<?> Findclass (String name)throwsClassNotFoundException {Throw Newclassnotfoundexception (name); }}
1.7 Custom class Loader implementation
Filesystemclassloader is a custom class loader that inherits from Java.lang.ClassLoader and is used to load classes on the file system. It first finds the class's byte code file (. class file) on the file system based on the full name of the class, then reads the contents of the file, and finally converts the byte code into an instance of the Java.lang.Class class by using the DefineClass () method.
Java.lang.ClassLoader's LoadClass () implements the logic of the parent delegation model, so the custom classloader generally does not rewrite it, but the Findclass () method needs to be rewritten.
Public classFilesystemclassloaderextendsClassLoader {PrivateString RootDir; PublicFilesystemclassloader (String rootdir) { This. RootDir =RootDir; } protectedClass<?> Findclass (String name)throwsClassNotFoundException {byte[] Classdata =getclassdata (name); if(Classdata = =NULL) { Throw Newclassnotfoundexception (); } Else { returnDefineClass (name, Classdata, 0, classdata.length); } } Private byte[] Getclassdata (String className) {string path=Classnametopath (className); Try{InputStream ins=NewFileInputStream (path); Bytearrayoutputstream BAOs=NewBytearrayoutputstream (); intBufferSize = 4096; byte[] buffer =New byte[buffersize]; intBytesnumread; while((Bytesnumread = ins.read (buffer))! =-1) {baos.write (buffer,0, Bytesnumread); } returnBaos.tobytearray (); } Catch(IOException e) {e.printstacktrace (); } return NULL; } Privatestring Classnametopath (String className) {returnRootDir +File.separatorchar+ classname.replace ('. ', File.separatorchar) + ". Class"; }}
[Chen Wenwen 1] program code
[Chen Wenwen 2] so the assignment action of the class variable + statement in the static statement block.
Note: A static statement block can only access the class variable that is defined before it, and the subsequent value is assignable and inaccessible.
[Chen Wenwen 3] The virtual machine guarantees that the parent class construct is called before the subclass is called. The parent class is Java.lang.Object
[Chen Wenwen 4] when a class (interface) does not contain a static statement block, and there is no assignment to the class variable, the compiler does not call the construct.
There is no static code block in the [Chen Wenwen 5] interface, but the assignment of class variable initialization will generate the <clinit> () method. However, the <clinit> () method of the parent class is not executed in the interface (Implementation Class). Executes only when a variable of the parent class is used.
[Chen Wenwen 6] the <clinit> () method of the automatic wrapper class for virtual machines is properly locked and synchronized under multithreading.
- [Chen Wenwen 7] subclass accesses static fields of parent class, does not initialize subclasses
- Array definition to refer to the class, not to start this class. Initializes an array class. Inherits the subclass of object. Array properties and methods.
- Constants are stored in a constant pool in the calling class in the compile phase, not directly referenced to the class in which they are located.
Java Virtual Machine (4)--Class loading mechanism