The class loading system loads classes in three steps, loading, linking, and initializing, which are described below.
Class loading subsystem architecture diagram:
1 Class Loader
The JVM uses class loaders to load class files, which can be categorized asBootstrap Class Loadercap (a poem)Custom Class LoaderTwo kinds.
The Bootstrap ClassLoader, sometimes called the bootstrap class loader or the Null ClassLoader, is one of the most basic class loaders in the Java Virtual Machine. Its main responsibility is to load the core Java class library.
Custom class loaders requireInherited from ClassLoader classThe JDK provides a number of them by default. Two of the more important ones are.Extended Class Loader (ExtClassLoader) cap (a poem)Application Class Loader (AppClassLoader) 。
The following is an expansion of what these three loaders do, how they differ, and how they are related. Let's start with a diagram:
1.1 BootStrapClassLoader
Features:
- internal implementation: The bootstrap class loader is not implemented in Java code, but is written in C++ or another native language and is part of the JVM.
-
Load Path: bootstrap class loaders usually start with the
$JAVA_HOME/jre/lib/
or a similar location to load Java core classes. - parentless class loader: The bootstrap class loader has no explicit parent class loader, because it is designed to load Java's most basic class libraries, which are a prerequisite for any other class loader to work. Therefore, it does not need to depend on any other class loader.
- invisibility: The bootstrap class loader is not visible to all Java applications because it is part of the JVM and not part of the standard Java class loader hierarchy.
- prioritization: The bootstrap class loader is usually the first step in the entire class loading process, loading the necessary core class libraries when a Java application is started before allowing subsequent class loaders, such as the extension class loader and the application class loader, to begin their work.
1.2 Extending the class loader (ExtClassLoader
)
Features:
-
internal implementation:
ExtClassLoader
Yes, it is.A static inner class within a class that inherits from the
ClassLoader
class, overriding theloadClass()
Methods. -
Load Path:
ExtClassLoader
It is primarily responsible for loading files that are located in the$JAVA_HOME/jre/lib/ext
Extension libraries in the directory. -
proxy model:
ExtClassLoader
follows the delegate model of Java class loaders. When it receives a class loading request, it first tries to load the class using its parent class loader (i.e. Bootstrap ClassLoader). If the parent class loader fails to load it, theExtClassLoader
Will try to load it myself. -
prioritization:
ExtClassLoader
be situated atBootstrapClassLoader
After that, but afterAppClassLoader
before. This means that it inherits theBootstrap ClassLoader
feature, and it loads a class that has no effect on theApplication ClassLoader
Visible.
1.3 Application Class Loader (AppClassLoader)
Features:
-
internal implementation:
AppClassLoader
Also inA static inner class within a class that inherits from the
ClassLoader
class, overriding theloadClass()
Methods. -
Load Path:
AppClassLoader
The main directory responsible is the current application'sclasspath
path, which means that the classes we write ourselves are by default passed through theAppClassLoader
loaded. When we run the code in IDEA, a close look at the console reveals that the first line is loaded via the-classpath
specifies the current application'sclass
Directory of documents -
proxy model:
AppClassLoader
follows the delegate model of Java class loaders. When it receives a class loading request, it first tries to use its parent class loaderExtClassLoader
to load the class. If the parent class loader fails to load it, theAppClassLoader
Will try to load it myself. -
prioritization:
AppClassLoader
be situated atExtClassLoader
After.
In addition to these features.AppClassLoader
There are a few other uses:
- Loading Third-Party Jar Packages: When an application relies on third-party libraries, these libraries are usually packaged as JAR packages and placed in the class path; AppClassLoader loads the classes in these JAR packages.
- Dynamically loaded classes: In scenarios where classes need to be loaded dynamically, such as Spring Boot applications, AppClassLoader can be used to load and unload classes dynamically.
1.4 Parental Assignment
Reason 1: Earlier we introduced the bootstrap class loader, the extension class loader, and the application class loader are each responsible for different paths under theclass
files, but are not completely disjoint, such as the-classpath
In addition to specifying the current application'sclass
In addition to the file directory, it also specifies the$JAVA_HOME/jre/lib/
directory, so avoid reloading certain classes.
Reason 2: If our program is hacked, for example, the hacker creates his own package, which creates a class named String, and implants this package and class into our running project, if his class is loaded, the String in our project will be tampered with.
To avoid both of these reasons, we want to make sure that classes are loaded only once, and that the closer to the JVM the class loader is prioritized. This is what the two parent delegate does!!!!
Principle:
There is a relationship between the bootstrap class loader, the extension class loader, and the application class loader, but it's not a parent-child relationship; instead, the application class loader has a parent attribute that is an object of the extension class loader. The extension class loader has an empty parent, so it calls the bootstrap class loader. Let's observeClassLoader
(used form a nominal expression)loaderClass()
method yields the class loading process:
The short answer is.
When loading a class through AppClassLoader, ExtClassLoader will be used to load the class first;
When loading a class via ExtClassLoader, BootStrapClassLoader is used to load the class first;
Benefits:
- Avoid classes being loaded repeatedly.
- Prevents JVM core classes from being tampered with.
2 Links
After the class is loaded it will be linked, in three steps: validation, preparation, and parsing.
2.1 Validation
The first step is to verify that the class file is correct, such as verifying the format.
2.2 Preparation
A default value is assigned to the static-modified property, but no initial value is assigned in this step.
For example, if a class defines a static int a = 1, the preparation phase assigns a to 0, and a = 1 during the initialization phase.
2.3 Parsing
Resolve symbolic references to direct references. What does it mean?
The first thing we need to know is that classes are loaded into the method area, and each class is a Klass object (which can also be called a Klass structure).
Normally we would use a class A in a class B, using the fully-qualified name of the class B, which is just a string. However, the JVM actually needs to find the Klass object of class B from the method area when executing, and the role of parsing is to replace the name string with the actual Klass object memory address. The "symbolic reference" is the name string, and the "direct reference" is the memory address of the Klass object.
3 Initialization
Initialization is the last phase of the class loading subsystem and one of the most critical. The contents of the initialization phase and its importance are described in detail below.
3.1 Definitions
The initialization phase is the last phase in the class loading process and it is responsible for executing the class constructor<clinit>
method and initializes the class's static variables.
3.2 Main tasks
The main tasks of the initialization phase include:
-
Execute the class constructor
<clinit>
methodologies:<clinit>
A method is a special static constructor that is responsible for initializing a class. Every class has a<clinit>
method, which is automatically generated and executed by the JVM when the class is first initialized. -
Initializing class variables: Static variables in a class (i.e., class variables) in the
<clinit>
method is assigned.
3.3 <clinit>
Characteristics of the methodology
-
static block: In class definitions, static code blocks are converted by the compiler into
<clinit>
statement in the method. - sequential execution: If a class has more than one static code block, they will be executed in the order in which they appear in the source code.
-
thread safety:
<clinit>
method is thread-safe, which means that even if more than one thread initializes the same class at the same time, there is no conflict.
3.4 Example code
Here is a simple example showing the initialization of the class:
public class InitializationExample {
static {
("Execute static initialization block。");
}
static int staticVar = initializeStaticVar();
private static int initializeStaticVar() {
("Initializing static variables。");
return 10;
}
public static void main(String[] args) {
("Static variables are initialized to: " + staticVar);
}
}
The output is as follows:
Execute the static initialization block.
Initialize static variables.
The static variable is initialized to: 10
3.5 Initialization Timing
Class initialization is usually triggered in the following cases:
- Creating an instance of a class for the first time: When an instance of a class is created for the first time, the JVM initializes the class.
- Calling static methods of a class: The JVM initializes the class the first time a static method of the class is called.
- Referencing static fields of a class: The JVM initializes the class the first time a static field of the class is referenced.
-
reflexive citation: When passing
maybe
When referring to a class by methods in a package, the JVM initializes the class if those methods cause the class to be initialized.
- When initializing subclasses: When initializing a subclass of a class, the JVM initializes the parent class first if the parent class has not already been initialized.
3.6 Initialization sequence
The order in which classes are initialized follows certain rules:
- If class A references a static field of class B or calls a static method of class B, then class B must be initialized before class A.
- If class A inherits from class B, then class B must be initialized before class A.