Java Class Loading
Class loading is the JVM process of finding class definitions, creating their runtime representation, linking them, and initializing them when required. Understanding the lifecycle helps explain classpath issues, initialization order, custom class loaders, and common `ClassNotFoundException` versus `NoClassDefFoundError` failures.
When the JVM needs a class, a class loader obtains its binary representation and defines a corresponding `Class` object. Loading is distinct from linking and initialization, although these phases are commonly discussed together as class loading. The JVM can defer loading and initialization until the class is actually needed.
Linking has three conceptual stages: verification checks that the class file is structurally and semantically valid for the JVM, preparation allocates and initializes memory for static fields to default values, and resolution converts symbolic references into direct references when required. Resolution may be performed lazily rather than all at once.
Initialization executes a class's initialization method, `<clinit>`, which contains static field initialization and static initialization blocks. Initialization occurs under JVM rules that establish when a class must be initialized, such as active use through certain static operations or creation of an instance. A superclass is initialized before its subclass.
The standard class-loader architecture commonly involves the bootstrap loader, platform loader, and application or system loader. Parent delegation means a loader generally asks its parent to load a class before attempting to load it itself. This reduces duplicate loading of core classes and helps maintain type identity and security boundaries.
A class's identity is determined by its binary name together with the defining class loader. Consequently, two loaders can define classes with the same binary name that the JVM treats as different types. This is important in application servers, plugin systems, modular runtimes, and hot-reloading mechanisms.
Key points
- Loading, linking, and initialization are distinct phases.
- Linking consists of verification, preparation, and resolution.
- Static initialization is performed through the class's `<clinit>` method.
- Parent delegation normally gives parent class loaders the first opportunity to load a class.
- Class identity includes both the binary name and defining class loader.
- Initialization is generally triggered by active use rather than merely referencing a class name.
Interview questions
What are the main phases involved when the JVM loads a class?
The process can be described as loading, linking, and initialization. Loading obtains the class bytes and creates the runtime representation. Linking includes verification, preparation, and resolution. Initialization executes static initialization code when the JVM determines that initialization is required.
What is parent delegation in Java class loaders?
With parent delegation, a class loader normally asks its parent to load a requested class before attempting to define it itself. This creates a hierarchy in which higher-level loaders commonly provide platform and core classes. It helps avoid accidentally loading another implementation of a fundamental class. Custom loaders can alter this strategy when an application needs different loading behavior.
When is a class initialized by the JVM?
Initialization occurs when the JVM encounters an operation that requires the class to be initialized, subject to the JVM's initialization rules. Typical examples include creating an instance and certain accesses to static members. Merely mentioning a class in source code does not necessarily initialize it. Before initializing a class, the JVM ensures that its relevant superclass initialization has occurred.
Why can two classes with the same fully qualified name be incompatible?
The JVM's notion of class identity includes the binary name and the defining class loader. Therefore, two different loaders can define separate classes that have identical binary names. The JVM can treat instances of those classes as unrelated types. This is a common source of `ClassCastException` in plugin architectures and container environments.
What is the difference between ClassNotFoundException and NoClassDefFoundError?
`ClassNotFoundException` is an exception commonly produced when code explicitly asks a class-loading mechanism to locate a class and the lookup fails. `NoClassDefFoundError` is an error indicating that the JVM cannot find or initialize a class definition that was expected to be available. The latter can also occur after an earlier attempt to initialize a class failed. Diagnosing the exact cause requires examining the complete exception chain and class-loader or dependency configuration.