Class Loading in Java: An In-Depth Exploration
The Java Development Kit (JDK) provides three default ClassLoaders, which play a crucial role in loading Java classes. These ClassLoaders are responsible for loading core Java class libraries, extension classes, and application-specific classes. In this article, we will delve into the world of ClassLoaders, exploring their hierarchical relationship and the delegation model that governs their behavior.
The Three Default ClassLoaders
- Bootstrap ClassLoader (Start Class Loader): Written in C++, this ClassLoader is responsible for loading core Java class libraries. The path for these libraries is specified by the
% JAVA_HOME% / jre / libparameter. Developers can also specify the path using the-Xbootclasspathparameter and the% JAVA_HOME% / jre / classesdirectory. - Extension ClassLoader (extension class loader): This ClassLoader is responsible for loading extension classes that extend the JVM libraries. The path for these libraries is specified by the
% JAVA_HOME% / jre / lib / extdirectory and thejava.ext.dirssystem variable. - Application ClassLoader (application loader): This ClassLoader is responsible for loading application-specific classes and is the default ClassLoader for Java programs. It loads classes from the specified classpath libraries.
Implementing Custom ClassLoaders
In addition to these three default ClassLoaders, developers can implement their own custom ClassLoaders according to their needs. This flexibility allows for the creation of specialized ClassLoaders that can load classes from specific locations or with specific characteristics.
The Hierarchical Model of ClassLoaders
The hierarchical relationship between ClassLoaders is typically as follows:
Bootstrap ClassLoader
|
|-- Extension ClassLoader
| |
| |-- Application ClassLoader
|
|-- Null (representing the starting ClassLoader)
This hierarchical relationship is demonstrated by the following code:
public class Test {
public static void main(String args[]) {
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(ClassLoader.getSystemClassLoader().getParent());
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
}
}
AppClassLoader …xtClassLoader …Null
Note that the last value is null, representing the starting ClassLoader, which is written in C++ and cannot be obtained directly.
The Class Loader Delegation Model
The delegation model between ClassLoaders is as follows:
- The top-level BootLoader Class is responsible for loading core Java class libraries.
- The rest of the ClassLoaders load classes by delegating to their parent ClassLoader.
- When a ClassLoader loads a class, it first requests the task from its parent ClassLoader.
- If the parent ClassLoader can complete the task successfully, it returns the loaded class.
- If the parent ClassLoader fails to load the class, the task is passed down to the next ClassLoader in the hierarchy.
The loadClass() Method
The loadClass() method in the java.lang.ClassLoader class demonstrates the delegation model:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// Check if class is loaded too
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// If the parent class is not empty then the parent class loader for delegation
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// empty parent class loader request to start
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// If the parent class throws an exception on behalf of the parent class can not be loaded
}
// parent class is not loaded
if (c == null) {
// use method to load itself findClass
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
In this article, we have explored the world of ClassLoaders in Java, including the three default ClassLoaders, the hierarchical relationship between ClassLoaders, and the delegation model that governs their behavior. We have also examined the loadClass() method in the java.lang.ClassLoader class, which demonstrates the delegation model.