Java 36: Class Loading & the Delegation Model
easy⏱ 5 mincoursejava
The three classloaders
Bootstrap (native, loads java.*, written in C++). Platform (loads JDK modules like java.sql, java.logging since Java 9). System (loads your app classpath and modules). Each has a parent; they form a chain rooted at Bootstrap.
Parent-first delegation
On loadClass(name): (1) check if already loaded — return. (2) Ask parent — if parent has it, use parent's version. (3) Only if parent fails, try to load from own sources. This means you cannot redefine java.lang.String — the Bootstrap loader always finds it first.
Class identity = (name + classloader)
A class is identified by its fully qualified name + the classloader that loaded it. com.foo.Bar loaded by ClassLoader A is a different type than the same name loaded by ClassLoader B. Assignments between them throw ClassCastException at runtime. This is how hot-reload frameworks isolate versions.
Build a delegation chain
Three simulated classloaders: Boot, Platform, App. Each has a knownClasses: Set<string>. load(name) delegates up first. Show: (1) java.lang.String resolves via Boot even if App has one. (2) com.myapp.Foo resolves via App. (3) Two App classloaders loading the same name yields distinct 'identities'.
Context classloader gotcha
Thread.currentThread().getContextClassLoader() is a thread-local hack for frameworks (JDBC, ServiceLoader) to escape strict delegation. If you've ever seen ClassNotFoundException in a plugin system, the context classloader is usually involved.
Quiz: Sealing core classes
Why does the JDK refuse to load a user-provided java.lang.String? Parent-first delegation + package sealing. Bootstrap has java.lang.String already — parent-first finds it before the app version. Also, the java.* package is sealed — only Bootstrap may define classes in it.