Class loading in Java
Bootstrap, platform and application loaders; parent delegation; loading, linking, initialization.
A chain of librarians
Classes are loaded lazily, by class loaders. The bootstrap loader (native code) loads core classes like String. The platform loader loads the other JDK modules. The application loader (named app) loads your classpath. Each one has a parent: app → platform → bootstrap.
Ask your parent first
With parent delegation, a loader asked for a class first passes the request up to its parent, all the way to bootstrap. Only if no parent can find it does the loader load it itself. So core classes always come from the JDK.
// app asked for "java.lang.String"
// -> platform? -> bootstrap: found it!
// app never loads its own copyWho loaded what?
What does this print?
ClassLoader app =
ClassLoader.getSystemClassLoader();
var boot = Object.class.getClassLoader();
System.out.println(app.getParent().getName());
System.out.println(boot);platform nullapp bootstrapplatform bootstrapsystem null
Show the answer
The app loader's parent is named **platform**. Object comes from the bootstrap loader, which lives in the JVM's native code and has no Java object, so it shows up as **null**.
Load, link, initialize
Loading reads the bytes and creates the Class object. Linking has three parts: verification (is the bytecode safe?), preparation (static fields allocated with default values like 0 or null) and resolution (symbolic references become direct ones). Finally, initialization runs static initializers and assignments.
Shadowing a JDK class
Your own java/lang/String.class on the classpath never wins: the app loader delegates to bootstrap, which already has the real String. And class loaders other than bootstrap are forbidden from defining classes in java.* packages anyway.
// classpath: java/lang/String.class (yours)
String s = "hi"; // still the JDK's StringSame bytes, same class?
Two different class loaders each load com.shop.Cart from identical bytes. Are they the same type at runtime?
Think about it, then reveal the answer
No. A runtime type is class name + defining loader. Casting one to the other fails with a ClassCastException like *Cart cannot be cast to Cart*.
App servers and plugins
Application servers, IDEs and plugin systems give each app or plugin its own class loader, so two apps can use different versions of a library. The flip side is the famous *X cannot be cast to X* error: the same class loaded twice by different loaders, passed across the boundary.
Key takeaways
- Bootstrap loader is native and shows up as null in Java
- Parent delegation stops apps from replacing core JDK classes
- Linking = verification, preparation, resolution
- A runtime type is identified by class name + defining loader
💡 Parent delegation is like asking your manager first: only if nobody above you can handle the request do you do it yourself.
Before Java 9, the platform loader was called the extension class loader and loaded JARs from a jre/lib/ext folder. Java 9's module system replaced it with the platform loader.
Practice questions
What does this print?
ClassLoader app =
ClassLoader.getSystemClassLoader();
System.out.println(app.getName());
System.out.println(app.getParent().getName());
System.out.println(
String.class.getClassLoader());- app bootstrap null
- system platform bootstrap
- app platform bootstrap
- app platform null
Check your answer
app platform null. The application loader is named "app" and its parent is the "platform" loader. String comes from the bootstrap loader, which Java represents as null.
You put your own java/lang/String.class on the classpath, hoping to patch String. What happens?
- Every class that uses String fails to compile
- Loading is delegated to the parent first, so the JDK's String is used
- Your String replaces the JDK's for the whole app
- Both versions load and the JVM picks one at random
Check your answer
Loading is delegated to the parent first, so the JDK's String is used. The application loader delegates to its parents, and the bootstrap loader already provides java.lang.String. App loaders are also forbidden from defining classes in java.* packages.