| title | Detailed Explanation of Class Loaders (Key Points) | |
|---|---|---|
| category | Java | |
| tag |
|
Before introducing class loaders and the parent delegation model, let's briefly review the class loading process.
- Class loading process: Loading -> Linking -> Initialization.
- The linking process can be further divided into three steps: Verification -> Preparation -> Resolution.
Loading is the first step in the class loading process, mainly completing the following three tasks:
- Obtaining the binary byte stream that defines the class through its fully qualified name.
- Converting the static storage structure represented by the byte stream into a runtime data structure in the method area.
- Generating a
Classobject in memory that represents the class, serving as an access point for these data in the method area.
Class loaders have been around since JDK 1.0, initially created to meet the needs of Java Applets (which have since been deprecated). Over time, they have become an important part of Java programs, enabling Java classes to be dynamically loaded into the JVM and executed.
According to the official API documentation:
A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.
Every Class object contains a reference to the ClassLoader that defined it.
Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.
In summary, it means:
A class loader is an object responsible for loading classes.
ClassLoaderis an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.Every Java class has a reference pointing to the
ClassLoaderthat loaded it. However, array classes are not created byClassLoader, but are automatically created by the JVM when needed. TheClassLoaderfor an array class, when obtained viagetClassLoader(), is the same as that of its element type.
From the above introduction, we can see:
- A class loader is an object responsible for loading classes, implementing the loading step in the class loading process.
- Every Java class has a reference pointing to the
ClassLoaderthat loaded it. - Array classes are not created by
ClassLoader(array classes do not have corresponding binary byte streams) but are generated directly by the JVM.
class Class<T> {
...
private final ClassLoader classLoader;
@CallerSensitive
public ClassLoader getClassLoader() {
//...
}
...
}In simple terms, the main function of a class loader is to dynamically load the bytecode of Java classes (.class files) into the JVM (creating a Class object in memory that represents the class). The bytecode can be derived from Java source code (.java files) compiled by javac, or it can be dynamically generated by tools or downloaded over the network.
In addition to loading classes, class loaders can also load resources required by Java applications, such as text, images, configuration files, videos, and other file resources. This article will only discuss its core function: loading classes.
When the JVM starts, it does not load all classes at once but dynamically loads them as needed. This means that most classes are loaded only when they are actually used, which is more memory-friendly.
Classes that have already been loaded are stored in the ClassLoader. During class loading, the system first checks whether the current class has already been loaded. If it has, the loaded class is returned directly; otherwise, it attempts to load it. In other words, for a class loader, a class with the same binary name will only be loaded once.
public abstract class ClassLoader {
...
private final ClassLoader parent;
// Classes loaded by this class loader.
private final Vector<Class<?>> classes = new Vector<>();
// Called by VM to record each loaded class with this class loader.
void addClass(Class<?> c) {
classes.addElement(c);
}