The class loader subsystem's responsibilities are not limited to just locating and importing the binary data for classes. It also verifies that the imported classes are correct, allocates and initializes memory for class variables, and assists in resolving symbolic references. These activities are performed in a strict order:
Loading: The class loader reads the .class file and finds and imports binary data for a type.
Linking: It performs verification, preparation, and (optionally) resolution:
Verification: Ensures the correctness of the imported type
Preparation: Allocates memory to class variables and initializes the memory to default values
Resolution: Transforms symbolic references from the type into direct references
Initialization: Assigns values to all static variables defined in the code and executes static block (if any). Execution occurs from top to bottom in a class, and from parent to child in a class hierarchy.
In general, there are three class loaders:
Bootstrap class loader: This loads core-trusted Java API classes located in the JAVA_HOME/jre/lib directory. These Java APIs are implemented in native languages, such as C or C++.
Extension class loader: This inherits the Bootstrap class loader. It loads the classes from extension directories located at JAVA_HOME/jre/lib/ext, or any other directory specified by the java.ext.dirs system property. It is implemented in Java by the sun.misc.Launcher$ExtClassLoader class.
System class loader: This inherits the extension class loader. It loads classes from our application classpath. It uses the java.class.path environment variable.