ClassLoader: Bootstrap, Platform, App & Parent Delegation
- Last updated
- Prerequisites:
- Java class loading basics
- Understanding of JVM startup and the classpath
- java
- classloader
- bootstrap
- platform
- parent-delegation
- jvm
Read at your depth
The practical view
The JVM loads classes with three built-in loaders: the Bootstrap ClassLoader (JDK core classes like java.lang, java.util — implemented natively, no parent), the Platform ClassLoader (JDK modules, previously called Extension), and the Application/System ClassLoader (your classpath). The parent-delegation model: when asked to load a class, a loader first asks its parent, and only tries to load it itself if the parent fails. This ensures core classes are always the JDK's version. Custom loaders (ClassLoader subclasses) can break delegation by overriding loadClass, useful for plugin systems and hot reload.
The same idea in other frameworks
N/A — JVM runtime concern.N/A — JVM concern.N/A — JVM concern.N/A — JVM concern.Legacy vs modern
Classpath conflicts with multiple versions vs consistent delegation
Without delegation, two loaders could load different versions of the same class, breaking type identity; parent-first delegation guarantees one canonical version.
lib-a/lib/log4j.jar:1.2 lib-b/lib/log4j.jar:1.1 # ❌ OLD: two versions, chaosclass PluginLoader extends ClassLoader {
// ✅ NEW: child-first for plugin libs, parent-first for JDK classes
}Interview gotchas
Context
This tests the core delegation rationale — interviewers want the type-identity model and why breaking delegation causes ClassCastException, a classic debugging trap.
The mechanical answer
Parent-first delegation means loadClass asks the parent before searching its own namespace, so a class name resolves to the FIRST loader up the chain that can provide it — giving one canonical definition per class name in the hierarchy. Class identity in the JVM is (classloader, fully-qualified-name): two loaders that both load com.example.Foo define two DISTINCT types, even with identical bytecode. If a parent-loaded class references a class defined by a child loader and vice versa, casts between them fail with ClassCastException (or you get LinkageError on conflicting definitions). This is why plugin systems and app servers isolate each deployment with its own loader while delegating shared/JDK classes upward — the delegation boundary is exactly the type-identity boundary.
Trap
The naive answer is 'delegation prevents loading the same file twice'. It prevents two DIFFERENT loaders from defining the same name when a parent can provide it, which is about type identity, not file caching. Another trap: seeing ClassCastException and assuming a logic bug — it's often a loader mismatch (e.g. a class loaded by the app loader vs a child loader). Candidates who mention the (loader, name) identity tuple show real understanding.
Context
This probes the ClassLoader API mechanics — interviewers want the delegation-preserving override points and the linking step that defineClass triggers.
The mechanical answer
loadClass implements the delegation algorithm (cache check, parent delegation, then findClass); overriding it breaks or customizes delegation. findClass is the hook for loading bytes from your own source (a directory, a network, a DB) — overriding findClass while leaving loadClass alone preserves parent-first delegation, which is the recommended pattern. defineClass converts the byte array into a Class object: it calls into the VM's SystemDictionary to create/register the Klass, and triggers the linking phase (verification, preparation, resolution) lazily. Classes are initialized (static initializers) when first actively used, separately from loading/linking. The correct design: override findClass for custom byte sources; override loadClass only for deliberate child-first or isolation semantics (and even then, delegate JDK classes upward).
Trap
The naive answer is 'override loadClass to load from a new location'. The delegation-preserving way is findClass. Another trap: calling defineClass directly with unverified bytes — verification is part of linking and can be skipped (defineClass with the verify flag) but that's unsafe. Candidates who describe the three-method split and the SystemDictionary registration show real JVM knowledge.