[{"data":1,"prerenderedAt":107},["ShallowReactive",2],{"qa-\u002Fjava\u002Fjvm-internals\u002Fclassloading":3},{"page":4,"siblings":95,"blog":104},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":90,"topic":91,"topicSlug":92,"updated":93,"__hash__":94},"qa\u002Fjava\u002Fjvm-internals\u002Fclassloading.md","Classloading",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"hard","md","Java","java",{},true,3,"\u002Fjava\u002Fjvm-internals\u002Fclassloading",[23,28,33,37,41,45,49,53,57,61,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"what-is-classloading","easy","What is class loading in the JVM?","**Class loading** is the process by which the JVM reads a `.class` file\n(bytecode), parses it, and creates the corresponding `java.lang.Class`\nobject in memory. A class is loaded **on demand** the first time it is\nreferenced by running code — not upfront at JVM startup.\n\n```java\n\u002F\u002F When this line executes for the first time:\nMyService svc = new MyService();\n\u002F\u002F The JVM loads MyService.class if it hasn't been loaded yet,\n\u002F\u002F resolves its dependencies, initialises static fields, then calls new.\n```\n\n**Rule of thumb:** classes are loaded lazily; the JVM only reads a\n`.class` file the first time that class is actually needed.\n",{"id":29,"difficulty":30,"q":31,"a":32},"classloader-types","medium","What are the built-in ClassLoaders in the JVM and what does each load?","The JVM ships with a **hierarchy of ClassLoaders**:\n\n| ClassLoader | Java 8 name | Java 9+ name | Loads |\n|---|---|---|---|\n| Bootstrap | Bootstrap CL | Bootstrap CL | Core JDK classes (`java.lang.*`, `java.util.*`) from `rt.jar` \u002F `java.base` module |\n| Extension \u002F Platform | Extension CL | Platform CL | `javax.*`, security providers; in Java 9+ it loads named JDK modules not in `java.base` |\n| Application | App \u002F System CL | App CL | Classes from the user **classpath** (`-cp`) or module path |\n\n```java\nSystem.out.println(String.class.getClassLoader());        \u002F\u002F null (Bootstrap)\nSystem.out.println(ClassLoader.getSystemClassLoader());   \u002F\u002F AppClassLoader\nSystem.out.println(MyApp.class.getClassLoader());         \u002F\u002F AppClassLoader\n```\n\n**Rule of thumb:** `null` for a class's ClassLoader means it was loaded by\nthe Bootstrap ClassLoader — the JVM doesn't expose a Java object for it.\n",{"id":34,"difficulty":30,"q":35,"a":36},"delegation-model","What is the parent-delegation model for class loading?","Before loading a class, a ClassLoader **delegates to its parent** first.\nIf the parent (or its parent) can load the class, that result is used.\nOnly if the parent chain cannot find the class does the current loader\nattempt to load it itself. This ensures that core JDK classes loaded by\nBootstrap always take precedence.\n\n```\nAppClassLoader.loadClass(\"com.example.MyClass\")\n    → delegates to PlatformClassLoader\n        → delegates to BootstrapClassLoader\n            → not found in rt.jar \u002F java.base\n        ← BootstrapClassLoader returns null\n    ← PlatformClassLoader returns null\n→ AppClassLoader loads from classpath ✓\n```\n\n**Rule of thumb:** parent-delegation prevents a rogue `java\u002Flang\u002FString.class`\non the classpath from shadowing the real `String` — the Bootstrap loader\nalways wins for JDK classes.\n",{"id":38,"difficulty":30,"q":39,"a":40},"loading-linking-initialisation","What are the three phases of class loading — loading, linking, and initialisation?","**Loading** — reads the binary class data (from a file, JAR, network, etc.)\nand creates the `Class\u003C?>` object. The bytecode is not yet verified.\n\n**Linking** — three sub-steps:\n1. **Verification** — checks that the bytecode is structurally correct and\n   won't violate JVM safety guarantees.\n2. **Preparation** — allocates memory for static fields and sets them to\n   their **default values** (`0`, `null`, `false`) — *not* the values in\n   initialiser code yet.\n3. **Resolution** — resolves symbolic references (class names, method\n   descriptors) in the constant pool to actual memory addresses (optional\n   at link time; may be deferred).\n\n**Initialisation** — runs the class's `\u003Cclinit>` method (static initialisers\nand static field assignments) **exactly once**, the first time the class\nis actively used.\n\n```java\nclass Config {\n    static int LIMIT = Integer.parseInt(System.getenv(\"LIMIT\")); \u002F\u002F runs in \u003Cclinit>\n}\n```\n\n**Rule of thumb:** static fields are zeroed during *preparation*, then set\nto their real values during *initialisation* — never assume a static field\nholds its declared value before the class is initialised.\n",{"id":42,"difficulty":30,"q":43,"a":44},"class-identity","What is class identity in the JVM and why can two classes with the same name be different?","A class in the JVM is identified by **both its fully qualified name and its\nClassLoader**. Two `Class\u003C?>` objects are the **same class** only if both\nthe name and the ClassLoader instance match.\n\nThis is why frameworks like Java EE application servers, OSGi, and hot-deploy\nsystems use **separate ClassLoaders per deployment** — each application gets\nits own `com.example.Service`, isolated from others.\n\n```java\nClassLoader cl1 = new URLClassLoader(urls);\nClassLoader cl2 = new URLClassLoader(urls);\nClass\u003C?> a = cl1.loadClass(\"com.example.Foo\");\nClass\u003C?> b = cl2.loadClass(\"com.example.Foo\");\nSystem.out.println(a == b);              \u002F\u002F false — different loaders\nSystem.out.println(a.equals(b));         \u002F\u002F false\n\u002F\u002F Casting between them would throw ClassCastException\n```\n\n**Rule of thumb:** class identity = (fully-qualified name, ClassLoader);\nthe same `.class` file loaded by two different ClassLoaders produces two\nincompatible types.\n",{"id":46,"difficulty":30,"q":47,"a":48},"classnotfoundexception-vs-noclassdeffounderror","What is the difference between ClassNotFoundException and NoClassDefFoundError?","| | `ClassNotFoundException` | `NoClassDefFoundError` |\n|---|---|---|\n| Type | Checked exception | Error (unchecked) |\n| When | `Class.forName()`, `ClassLoader.loadClass()` called explicitly and the class is not on the classpath | Class was available at **compile time** but missing at **runtime** (e.g., JAR not deployed) |\n| Cause | Developer error: typo in class name, missing dependency at runtime | Deployment error: class was compiled against a JAR that is absent at runtime |\n\n```java\n\u002F\u002F ClassNotFoundException — explicit dynamic load\nClass.forName(\"com.mysql.jdbc.Driver\"); \u002F\u002F throws if MySQL JAR is missing\n\n\u002F\u002F NoClassDefFoundError — implicit reference to a class present at compile time\n\u002F\u002F but missing at runtime — JVM throws this from its own resolution code\n```\n\n**Rule of thumb:** `ClassNotFoundException` = you asked for a class by name\nand it wasn't there; `NoClassDefFoundError` = the JVM needed a class while\nloading another and couldn't find it.\n",{"id":50,"difficulty":14,"q":51,"a":52},"custom-classloader","Why would you write a custom ClassLoader and how do you do it?","Custom ClassLoaders let you load classes from non-standard sources:\nencrypted JARs, databases, over a network, generated bytecode at runtime,\nor isolated namespaces (plugins, hot-reload, OSGi bundles).\n\n```java\npublic class EncryptedClassLoader extends ClassLoader {\n    private final Path jarPath;\n\n    EncryptedClassLoader(Path p, ClassLoader parent) {\n        super(parent);           \u002F\u002F always wire up the parent for delegation\n        this.jarPath = p;\n    }\n\n    @Override\n    protected Class\u003C?> findClass(String name) throws ClassNotFoundException {\n        byte[] decrypted = decrypt(readBytesFromJar(jarPath, name));\n        return defineClass(name, decrypted, 0, decrypted.length);\n    }\n}\n```\n\nOverride `findClass()`, not `loadClass()`, to preserve the parent-delegation\nmodel. Call `defineClass()` with the raw bytecode to register the class with\nthe JVM.\n\n**Rule of thumb:** override `findClass()`, not `loadClass()` — breaking\ndelegation opens the door to shadowing core JDK classes.\n",{"id":54,"difficulty":14,"q":55,"a":56},"class-unloading","When does the JVM unload a class and why is this important for dynamic systems?","A class can be **unloaded** (and its `Class\u003C?>` object GC'd) only when\nits **ClassLoader** instance becomes unreachable. The Bootstrap ClassLoader\nnever becomes unreachable, so core JDK classes are never unloaded. Classes\nloaded by the Application ClassLoader are effectively permanent too (the\nloader lives as long as the JVM).\n\nClasses *can* be unloaded when:\n- They were loaded by a **custom ClassLoader** (e.g., a plugin loader).\n- All Class objects, all instances, and the ClassLoader itself have no\n  strong references.\n\n```java\nURLClassLoader pluginLoader = new URLClassLoader(urls, parent);\nClass\u003C?> pluginClass = pluginLoader.loadClass(\"com.plugin.Plugin\");\n\u002F\u002F ... use the plugin ...\npluginLoader.close();    \u002F\u002F no more strong ref to loader or class\npluginLoader = null;\n\u002F\u002F Now the GC can unload the plugin class and reclaim Metaspace\n```\n\nMetaspace leaks in hot-deploy scenarios (e.g., Tomcat web app reload) are\nalmost always caused by something outside the webapp's ClassLoader still\nholding a reference to the loader or one of its classes.\n\n**Rule of thumb:** if Metaspace grows after each hot-deploy, hunt for\nreferences to the old ClassLoader held in static fields or thread locals.\n",{"id":58,"difficulty":30,"q":59,"a":60},"static-initialiser","What guarantees does the JVM provide about class initialisation and static initialisers?","The JVM guarantees that a class's `\u003Cclinit>` (static initialiser block and\nstatic field assignments) runs **exactly once**, **before** any instance of\nthe class is created or any static member is accessed, and is\n**thread-safe** — the JVM uses an internal lock so that even if two threads\nrace to initialise the same class, only one runs `\u003Cclinit>` and the other\nwaits.\n\n```java\nclass Singleton {\n    private static final Singleton INSTANCE = new Singleton(); \u002F\u002F safe, runs once\n\n    static {\n        System.out.println(\"Initialising Singleton\");\n    }\n}\n```\n\nThis guarantee is what makes the **Initialization-on-demand Holder** idiom\nthread-safe without explicit synchronisation:\n\n```java\nclass Holder {\n    private Holder() {}\n    private static class Inner { static final Holder INSTANCE = new Holder(); }\n    static Holder getInstance() { return Inner.INSTANCE; }\n}\n\u002F\u002F Inner is not loaded until getInstance() is first called;\n\u002F\u002F JVM ensures thread-safe single initialisation\n```\n\n**Rule of thumb:** static initialisers are guaranteed to run once and\nsafely — this is the foundation of the holder singleton pattern.\n",{"id":62,"difficulty":25,"q":63,"a":64},"class-forname","What does Class.forName() do and what are its overloads?","`Class.forName(String name)` loads and **initialises** the named class\nusing the calling class's ClassLoader. The two-argument overload gives you\ncontrol over both:\n\n```java\n\u002F\u002F Simple form: loads + initialises using caller's ClassLoader\nClass\u003C?> clazz = Class.forName(\"com.example.MyPlugin\");\n\n\u002F\u002F Full control: Class.forName(name, initialize, loader)\nClass\u003C?> lazy = Class.forName(\"com.example.MyPlugin\",\n                              false,              \u002F\u002F don't initialise yet\n                              customLoader);      \u002F\u002F use this ClassLoader\n```\n\nThe classic use case is **JDBC driver registration** (pre-JDBC 4):\n`Class.forName(\"com.mysql.jdbc.Driver\")` loaded and initialised the driver\nclass, whose static block registered it with `DriverManager`. JDBC 4+\nuses `ServiceLoader` to do this automatically.\n\n**Rule of thumb:** `Class.forName(name)` = load + initialise;\n`Class.forName(name, false, loader)` = load only, defer initialisation.\n",{"id":66,"difficulty":14,"q":67,"a":68},"module-system-classloading","How did the Java 9 module system change class loading?","Before Java 9, the JDK was a monolithic `rt.jar` loaded by Bootstrap.\nJava 9 introduced the **module system (JPMS)**, splitting the JDK into\nnamed modules (`java.base`, `java.sql`, `java.logging`, etc.).\n\nKey changes:\n- **Bootstrap ClassLoader** now loads only `java.base` and a few core\n  modules; no more `rt.jar`.\n- **Platform ClassLoader** (renamed from Extension CL) loads the remaining\n  JDK modules.\n- Module boundaries enforce **strong encapsulation** — a module must\n  explicitly `exports` a package for code in other modules to access it;\n  deep reflection into non-exported packages requires `--add-opens`.\n\n```bash\n# Allow reflection into java.base internals (needed by some frameworks):\njava --add-opens java.base\u002Fjava.lang=ALL-UNNAMED -jar myapp.jar\n```\n\nClass loading *mechanics* (parent delegation, `defineClass`) are unchanged;\nwhat changed is the *source* of classes and what is accessible.\n\n**Rule of thumb:** JPMS changes *where* classes come from and *what* is\naccessible; the fundamental ClassLoader delegation chain still applies.\n",{"id":70,"difficulty":30,"q":71,"a":72},"serviceloader","What is ServiceLoader and how does it relate to class loading?","`java.util.ServiceLoader` is a lightweight **plugin \u002F SPI mechanism** that\ndynamically discovers and loads implementations of an interface registered\nin `META-INF\u002Fservices\u002F\u003Cinterface-name>` (or via `module-info.java`\n`provides` in modules).\n\n```java\n\u002F\u002F In META-INF\u002Fservices\u002Fcom.example.Plugin:\n\u002F\u002F com.example.impl.FooPlugin\n\nServiceLoader\u003CPlugin> loader = ServiceLoader.load(Plugin.class);\nfor (Plugin p : loader) {\n    p.execute(); \u002F\u002F each registered implementation is loaded and instantiated\n}\n```\n\nJDBC 4.0 drivers use `ServiceLoader` to auto-register without\n`Class.forName()`. Frameworks like SLF4J, Jackson, and JCA rely on it\nfor extensibility.\n\n**Rule of thumb:** `ServiceLoader` is the standard way to decouple an API\nfrom its implementation — prefer it over `Class.forName()` for plugin\narchitectures.\n",{"id":74,"difficulty":14,"q":75,"a":76},"classloader-leak","What is a ClassLoader leak and how do you detect and fix it?","A **ClassLoader leak** occurs when a custom ClassLoader (e.g., a web app\nloader in Tomcat) cannot be garbage collected after the app is undeployed\nbecause something outside the loader still holds a reference to it or to\na class\u002Fobject loaded by it. Because the loader can't be GC'd, neither can\nany of its classes — Metaspace grows with each redeploy.\n\nCommon causes:\n- **ThreadLocal values** whose type was loaded by the webapp loader, not\n  cleared before undeployment.\n- **Static fields in a shared library** (loaded by the parent ClassLoader)\n  holding a reference to an object of a webapp class.\n- **JDBC drivers** registered with `DriverManager` and never deregistered.\n- **Logging frameworks** holding class references in static config.\n\n```java\n\u002F\u002F Fix: deregister on shutdown\n@Override\npublic void contextDestroyed(ServletContextEvent sce) {\n    Enumeration\u003CDriver> drivers = DriverManager.getDrivers();\n    while (drivers.hasMoreElements()) DriverManager.deregisterDriver(drivers.nextElement());\n    \u002F\u002F Also clear any ThreadLocals your code set\n}\n```\n\nDetect with a heap dump: look for `ClassLoader` instances that should have\nbeen unloaded; trace their retaining references with Eclipse MAT.\n\n**Rule of thumb:** every object allocated in a web app that lives beyond\nthe request must be cleaned up in a `ServletContextListener.contextDestroyed`\n— otherwise it anchors the ClassLoader forever.\n",{"id":78,"difficulty":30,"q":79,"a":80},"bootstrap-classloader","Why does String.class.getClassLoader() return null?","The **Bootstrap ClassLoader** is implemented in native code (C\u002FC++) inside\nthe JVM itself, not as a Java class. It has no Java object representation,\nso the JVM signals \"loaded by Bootstrap\" by returning **`null`** from\n`getClassLoader()`.\n\n```java\nSystem.out.println(String.class.getClassLoader());         \u002F\u002F null\nSystem.out.println(int.class.getClassLoader());            \u002F\u002F null (primitive)\nSystem.out.println(MyApp.class.getClassLoader());          \u002F\u002F sun.misc.Launcher$AppClassLoader\n```\n\nThis is a conventional signal, not an error. Code that uses ClassLoaders\nmust handle `null` and interpret it as Bootstrap:\n\n```java\nClassLoader cl = SomeClass.class.getClassLoader();\nClassLoader toUse = (cl != null) ? cl : ClassLoader.getSystemClassLoader();\n```\n\n**Rule of thumb:** `null` ClassLoader = Bootstrap = JDK core class; always\nnull-check before using a class's ClassLoader as an argument.\n",{"id":82,"difficulty":14,"q":83,"a":84},"hotswap-and-dynamic-reloading","How does Java support hot-swapping or dynamic class reloading?","The standard JVM supports limited **HotSwap** via JPDA (Java Platform\nDebugger Architecture) — you can redefine a class's method bodies at\nruntime in a debug session without restarting. It cannot change class\nstructure (fields, superclasses, interfaces).\n\nFor full hot-reload (new fields, new classes, new hierarchies), the two\napproaches are:\n\n1. **Reload via a new ClassLoader** — create a fresh `URLClassLoader`,\n   discard the old loader and all its instances, let GC clean up.\n   Used by Tomcat, OSGi, and Java EE containers.\n2. **Bytecode manipulation agents** — tools like **JRebel** or\n   **HotswapAgent** use the `java.lang.instrument` API to redefine class\n   bytecode at runtime, including structural changes. Requires a `-javaagent`\n   flag at startup.\n\n```bash\njava -javaagent:hotswap-agent.jar MyApp\n```\n\n**Rule of thumb:** for dev-time hot reload of full structural changes use\na ClassLoader-per-deployment strategy or an instrumentation agent; for\nminor method-body fixes in a running debugger, JPDA HotSwap is sufficient.\n",15,null,{"description":11},"Java class loading interview questions — ClassLoader hierarchy, delegation model, loading\u002Flinking\u002Finitialisation phases, custom ClassLoaders, class unloading, ClassNotFoundException vs NoClassDefFoundError, and module system changes.","java\u002Fjvm-internals\u002Fclassloading","Class Loading","JVM Internals","jvm-internals","2026-06-20","K2ocnQi7twugrD-1hx8TJCVNGyuBOlFfy2lyxSPDQ14",[96,100,103],{"subtopic":97,"path":98,"order":99},"Memory — Heap & Stack","\u002Fjava\u002Fjvm-internals\u002Fmemory-heap-stack",1,{"subtopic":101,"path":102,"order":12},"Garbage Collection","\u002Fjava\u002Fjvm-internals\u002Fgarbage-collection",{"subtopic":90,"path":21,"order":20},{"path":105,"title":106},"\u002Fblog\u002Fjava-classloading","Java Class Loading Explained — ClassLoaders, Delegation, and Metaspace Leaks",1782244117492]