Demystifying Java Class Loading: Steps, ClassLoaders, and Common Pitfalls
This article explains the Java class loading lifecycle, the different built‑in and custom ClassLoaders, the parent‑delegation model, reasons for breaking it (e.g., JDBC and Tomcat), how to implement custom loaders, hot‑deployment techniques, and includes typical interview code questions.
1. Class Loading Process
Loading
The binary data of the .class file is read into memory and placed in the method area; a java.lang.Class object is created to encapsulate the class data.
Verification
Ensures the byte‑code conforms to JVM requirements and does not threaten JVM security (file format, magic number, byte‑code verification, etc.).
Preparation
Allocates memory for static variables (non‑final) in the method area and sets default values. For example:
<code>private static int age = 26;</code>During preparation, age receives four bytes and is initialized to 0 , not 26 . Final fields are set at compile time.
Resolution
Symbolic references in the binary data are replaced with direct references.
Initialization
Executes the class initializer <clinit>() . At this stage, static fields receive their explicit values (e.g., age becomes 26 ).
Usage
Application code can now instantiate objects and invoke methods.
Unloading
When no longer referenced, the class can be reclaimed by GC.
2. Types of ClassLoaders and Their Scope
Bootstrap ClassLoader
Top‑level loader with no parent; loads core JDK classes such as java.lang.* from the path defined by sun.boot.class.path . Implemented in native JVM code.
Extension ClassLoader
Parent is Bootstrap. Loads classes from directories specified by java.ext.dirs or jre/lib/ext . Extends java.lang.ClassLoader .
Application ClassLoader
Parent is Extension. Loads classes from the classpath defined by java.class.path . Extends java.lang.ClassLoader .
User‑Defined ClassLoader
Custom loaders must extend java.lang.ClassLoader . Used for hot‑deployment, Tomcat, etc.
Configuration of the three built‑in loaders can be seen in the source of sun.misc.Launcher :
<code>// sun.misc.Launcher
public class Launcher {
// Bootstrap class path
private static String bootClassPath = System.getProperty("sun.boot.class.path");
// AppClassLoader extends URLClassLoader
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
final String var1 = System.getProperty("java.class.path");
}
}
// ExtClassLoader extends URLClassLoader
static class ExtClassLoader extends URLClassLoader {
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
String var0 = System.getProperty("java.ext.dirs");
}
}
}
</code>3. What Is Parent Delegation?
When a ClassLoader receives a load request, it first checks its cache; if not found, it delegates the request to its parent. This recursion continues up to the Bootstrap loader. If the top‑level loader cannot find the class, the request returns to the child loader; if still not found, a ClassNotFoundException is thrown.
Relevant source: java.lang.ClassLoader#loadClass(String, boolean)
4. Why Use Parent Delegation?
It prevents multiple copies of the same byte‑code in memory and ensures security. For example, overriding java.lang.Object without delegation could load an unsafe version; delegation guarantees that only the Bootstrap loader can load core Java classes.
5. Why Break the Parent Delegation Model?
JDBC
JDBC drivers are user‑provided JARs loaded by the Application ClassLoader, not the Bootstrap loader. To load them, the Thread Context ClassLoader is used, allowing the driver classes to be found.
Tomcat
Each web application has its own ClassLoader to avoid class conflicts between apps. Breaking delegation lets different apps load different versions of the same class without interference.
Java SPI (e.g., JDBC 4.0) uses this mechanism.
Hot‑deployment scenarios also require breaking delegation.
6. How to Break Parent Delegation
Override the loadClass method (not findClass ) in a custom ClassLoader, providing custom loading logic.
7. How to Create a Custom ClassLoader
Extend java.lang.ClassLoader and override findClass(String name) to return the appropriate Class object.
8. Hot‑Deployment Principle
By breaking parent delegation and customizing loadClass() to skip the cache lookup, each reload reads the latest byte‑code, enabling hot deployment.
9. Common Interview Questions
Question 1 : What is the output?
Answer: Compilation error due to illegal forward reference.
<code>public class Test1 {
static {
i = 2; // compile‑time error
System.out.println(i);
}
private static int i = 1;
}
</code>Question 2 : What is the output?
Answer: 1 and 3.
Explanation: During preparation, static fields are set to default values; the constructor increments them, resulting in value1 = 1 and value2 = 3 after initialization.
<code>public class Test2 {
private static Test2 test2 = new Test2();
private static int value1;
private static int value2 = 3;
private Test2() {
value1++;
value2++;
}
public static void main(String[] args) {
System.out.println(test2.value1); // 1
System.out.println(test2.value2); // 3
}
}
</code>Changing the order of field declarations changes the result (e.g., 1 and 4).
<code>public class Test3 {
private static int value1;
private static int value2 = 3;
private static Test3 test3 = new Test3();
private Test3() {
value1++;
value2++;
}
public static void main(String[] args) {
System.out.println(test3.value1); // 1
System.out.println(test3.value2); // 4
}
}
</code>Sanyou's Java Diary
Passionate about technology, though not great at solving problems; eager to share, never tire of learning!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.