A translation of the article was prepared specifically for students of the Java Developer course.
In this series of articles, I'll talk about how the Java Virtual Machine works. Today we look at the mechanism for loading classes in the
JVM .
The Java Virtual Machine is at the heart of the Java technology ecosystem. It makes it possible for Java programs to implement the principle of “write once run everywhere”. Like other virtual machines, the JVM is an abstract computer. The main task of the JVM is to load
class files and execute the
bytecode contained in them.
The JVM includes various components, such as a
Classloader ,
Garbage Collector (automatic memory management), an interpreter, a
JIT compiler, and flow control components. In this article, we will look at the class loader.
The class loader downloads class files for both your application and the Java API. Only those Java API class files that are really required when running the program are loaded into the virtual machine.
The byte code is executed by the execution engine.
What is class loading?
Class loading is the search and loading of types (classes and interfaces) dynamically during program execution. Type data is in binary class files.
Class loading steps
The class loader subsystem is not only responsible for finding and importing binary class data. It also performs validation of imported classes, allocates and initializes memory for class variables, and helps in resolving symbolic links. These actions are performed in the following order:
- Loading - searching and importing binary data for a type by its name, creating a class or interface from this binary representation.
- Linking - performing verification, preparation and, optionally, permission:
- Verification - verification of the correctness of the imported type.
- Preparation — allocating memory for static class variables and initializing memory with default values.
- Resolution - Convert symbolic type links to direct links.
- Initialization is a call to Java code that initializes class variables with their correct initial values.
Note - the class loader, in addition to loading classes, is also responsible for finding resources. A resource is some data (for example, a “.class” file, configuration data, images) that are identified using an abstract path separated by a “/” character. Resources are usually packaged with an application or library so that they can be used in application or library code.
Class loading mechanism in Java
Translator's note - this section describes the behavior for java <9, in java 9+ there have been small changes, which are described below.
Java uses the class loading delegation model. The basic idea is that each class loader has a “parent” loader. When a
class is
loading , the loader “delegates” the class search to its parent before searching for the class on its own.
The class loader delegation model is a graph of loaders that pass load requests to each other. The root of this graph is the bootstrap bootloader. Class loaders are created with one parent to whom they can delegate the load, and search for the class in the following places:
- Cache
- Parent
- Bootloader itself
The class loader first checks to see if it has loaded the class before. If so, then the same class that was returned the last time is returned (the class stored in the cache). If not, the ability to load the class is provided to the parent. These two steps are repeated recursively in depth. If the parent returns null (or throws a
ClassNotFoundException ), then the loader searches for the class on its own.
The class is loaded by the loader that is closest to the root, since the right to first load the class is always granted to the parent loader. This allows the loader to see only classes loaded independently by its parent or ancestors. It cannot see classes loaded by child loaders.
The Java SE Platform API has historically defined two class loaders:
Bootstrap class loader (basic, primary loader) - loads classes from bootstrap classpath.
System class loader - the parent class for new class loaders and, as a rule, the class loader used to load and run the application.
JDK 9+ Class Loaders
Application class loader - commonly used to load application classes from a classpath. It is also the default bootloader for some JDK modules that contain utilities or export the utilities API. (
Translator's note: for example, jdk.jconsole
, jdk.jshell
, etc. )
Platform class loader - loads the selected (based on security / permissions) Java SE and JDK modules. For example, java.sql.
Bootstrap class loader - Loads the core Java SE and JDK modules.
These three built-in class loaders work together as follows:
- The application class loader first looks for named modules specific to all built-in loaders. If a suitable module is defined for one of these loaders, then this loader loads the class. If the class is not found in the named module defined for one of these loaders, then the application class loader delegates it to the parent. If the class is not found by the parent, then the application class loader looks for it in the classpath. Classes found in the classpath are loaded as members of the unnamed module of this loader.
- The platform class loader searches for named modules defined for all built-in loaders. If a suitable module is defined for one of these loaders, then this loader loads the class. If the class is not found in the named module defined for one of these loaders, then the platform class loader delegates it to the parent.
- The bootstrap class loader searches for named modules defined for itself. If the class is not found in the named module defined for the bootstrap loader, then the bootstrap loader searches for files and directories added to the bootstrap classpath using the -Xbootclasspath / a parameter (allows you to add files and directories to the bootstrap classpath). Classes found in the bootstrap classpath are loaded as members of the unnamed module of this loader.
To view the built-in class loaders, you can use the following code:
package ru.deft.homework; import java.sql.Date; public class BuiltInClassLoadersDemo { public static void main(String[] args) { BuiltInClassLoadersDemo demoObject = new BuiltInClassLoadersDemo(); ClassLoader applicationClassLoader = demoObject.getClass().getClassLoader(); printClassLoaderDetails(applicationClassLoader);
By running this code on Amazon Corretto 11.0.3 installed on me, we get the following result:
ClassLoader name : app ClassLoader class : jdk.internal.loader.ClassLoaders$AppClassLoader ClassLoader name : platform ClassLoader class : jdk.internal.loader.ClassLoaders$PlatformClassLoader Bootstrap classloader
You can learn more about the ClassLoader API
here (JDK 11) .