- A classloader finds a class file and loads it into the JVM so the program can use it.
- Classes load on first use, not at startup, and the loader locates the bytecode each time.
- Built-in loaders form a parent chain (bootstrap, platform, application) that delegates upward.
- Custom classloaders are why Minecraft mods can patch game classes as they load.
A classloader is the part of the Java runtime that finds a class file and loads it into the JVM so the program can use it. Classes are not all loaded at startup. The JVM loads each one the first time it is needed, and a classloader is what locates the bytecode, reads it, and hands it to the JVM. Minecraft Java Edition runs on this exact mechanism.
Where Opal fits
Opal is a Fabric mod, and Fabric loads the game through its own classloader so mods can patch classes as they load. The setup guide walks through installing it.
What a classloader actually does
A classloader turns a class name into a usable class inside the running JVM. You ask for a type, the loader locates the matching .class bytes, and the JVM defines that type in memory.
The work happens in three steps. The loader finds the bytecode for a named class. The JVM verifies and links it. Then the class is ready to use. This is why a Java program can pull in code it never mentioned at compile time: the name is enough for the loader to go find it.
The loader hierarchy
Classloaders are arranged in a parent chain, and most of them ask their parent first. A standard application has three built-in loaders stacked on top of each other.
| Loader | Loads |
|---|---|
| Bootstrap | The core Java runtime classes |
| Platform | Standard library modules outside the core |
| Application | Your program's own classes from the classpath |
When the application loader is asked for a class, it normally delegates upward first. The parent gets the chance to load it, and only if no parent can does the child try. This is called the delegation model, and it keeps core types consistent across the whole program.
Class identity and custom loaders
A class is identified by both its name and the loader that defined it. Two loaders can each load a class with the same name, and the JVM treats them as two different types. This sounds like a detail, but it is the whole reason classloaders are powerful.
Programs can define their own classloaders. A custom loader can read bytecode from anywhere: a jar, the network, a generated byte array, even bytecode it transformed on the way in. This is how plugin systems, app servers, and mod frameworks load code that the host program never knew about at build time.
Why this matters for Minecraft mods
Mods exist because of custom classloading. A mod loader for Minecraft starts the game through its own classloader so it can see and modify game classes as they load. That hook point is where bytecode patching happens.
When a loader sits between the disk and the JVM, it can transform a class right before the JVM defines it. A mod can rewrite a game method, inject new behavior, or add fields, all without a modified copy of the game on disk. The class the JVM ends up running is the patched one. For how this fits into the wider picture, see What is a Minecraft mod loader?.
FAQ
On first use, not at startup. The first time your code touches a type, the JVM asks a classloader to find and define it. This is called lazy loading.
A loader asks its parent to load a class before trying itself. The parent chain runs up to the bootstrap loader, which keeps core Java types from being loaded twice under the same name.
Yes, if different classloaders define them. The JVM identifies a class by its name plus its defining loader, so same-named classes from separate loaders are distinct types.
To see game classes as they load and patch them in memory. A custom loader can transform bytecode before the JVM defines the class, which is how mods change the game without editing it on disk.