This is the 11th day of my participation in the August More text Challenge. For details, see: August More Text Challenge
preface
The first stage in the Class lifecycle is the Class loading stage, where the binary stream of non-array classes is loaded into memory and a Java.lang.class object is generated.
This article mainly discusses the story happened in this stage.
Class loaders
1.1 Class loader types
There are three important classloaders built into the JVM. With the exception of BootstrapClassLoader, all class loaders are implemented by Java and all inherit from Java.lang.ClassLoader
(Figure) Class loader hierarchy
For the JVM, there are two types of classloaders:
- Startup class loader: for the Hotsopt virtual machine, the startup class loader is implemented in C++ and is part of the virtual machine
- Other class loaders: These loaders are implemented in the Java language, are independent of the virtual machine, and are all inherited from
java.lang.ClassLoader
These class loaders need to be loaded into memory by the bootstrap class in order to load other classes
For developers, class loaders fall into three categories:
- Start the class loaderBootstrap ClassLoader: Is responsible for loading
${JAVA_HOME}/jre/lib
Directory, or by-Xbootclasspath
The class library in the path specified by the parameter can be identified by the VM. The startup class loader is not available to developers. - Extend the class loaderExtension ClassLoader: is mainly responsible for loading
%JRE_HOME%/lib/ext
Directory containing jar packages and classes, or byjava.ext.dirs
Jar package in the path specified by the system variable; Developers can use extension class loaders directly. - Application ClassLoader: a loader for our users that is responsible for loading all jar packages and classes in the current Application classpath; Developers can use the class loader directly.
1.2 Querying the classloader of the class
Example code:
public class Test {
public static void main(String[] args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); System.out.println(classLoader); System.out.println(classLoader.getParent()); System.out.println(classLoader.getParent().getParent()); }}Copy the code
Output:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@4eec7777
null
Copy the code
The third reason for null is because the HotSopt BootstrapClassLoader is implemented in C++ and cannot find a concrete object
1.3 Custom class loaders
Most of the time, we use the system classloader directly, but there are some that require our own class loader. For example, the bytecode files that are transmitted over the network are encrypted so that the system loader cannot load the classes
All class loaders except BootstrapClassLoader are implemented in Java and all inherit from Java.lang.ClassLoader. If we want to customize our own ClassLoader, we just need to inherit from ClassLoader
Ii. Parent delegation mechanism
Each class has its own ClassLoader, and classloaders in the system use parent delegation by default when working together
Parent delegation mechanism:
- During class loading, the system first determines whether the current class has been loaded. Classes that have already been loaded are returned directly, otherwise loading is attempted.
- When loading, the request is first delegated to the parent class loader
loadClass()
When the parent class loader is NULL, the bootstrap class loader is usedBootstrapClassLoader
As the parent class loader, all requests go to the startup class loader. - When the request arrives
BootstrapClassLoader
I’m going to check from top to bottom to see if it can be loaded until someone says yes.
2.1 Code implementation of the parent delegate mechanism
In the loadClass() of java.lang.classLoader
publicClass<? > loadClass(String name)throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronizedClass<? > loadClass(String name,boolean resolve) throws ClassNotFoundException {
// First check whether the type has been loaded
Class c = findLoadedClass(name);
if (c == null) {
// If it is not loaded, delegate to the parent class loader or delegate to the bootstrap class loader
try {
if(parent ! =null) {
// Delegate to the parent class loader, if it exists
c = parent.loadClass(name, false);
} else {
// If there is no parent Class loader, check if the Class was loaded by the bootstrap Class loader by calling the local method native Class findBootstrapClass(String name)c = findBootstrapClass0(name); }}catch (ClassNotFoundException e) {
// If neither the parent class loader nor the bootstrap class loader can complete the load task, the own load function is calledc = findClass(name); }}if (resolve) {
resolveClass(c);
}
return c;
}
Copy the code
2.2 Why use parent delegation
The parent delegate mechanism prevents classes from being loaded repeatedly, especially the core classes of the system.
If someone wants to replace the system-level class java.lang.String now, it has already been loaded by the BootstrapClassLoader under the parent delegation mechanism, and no other classloader has a chance to load it.
Thus, the parent delegate model ensures that Java programs run stably and that Java’s core APIS are not tampered with.
3. To summarize
The JVM class loading mechanism is summarized as follows:
- Overall delegation: When a classloader is responsible for loading a Class, other classes that that Class depends on and references are also responsible for loading by that Class loader, unless it is shown to be loaded by another classloader
- Caching mechanism: The caching mechanism ensures that all classes loaded are cached. When a Class needs to be used in the program, the Class loader first looks for the Class from the cache before executing the loading logic and storing it in the cache
- Parent delegation: If a classloader receives a class loading request, it does not first attempt to load the class itself. Instead, it delegates the request to the parent, and so on. If the parent class loader cannot load, go down