What is Java ClassLoader:
The term "class loading" refers to the process of locating the bytes for a given class name and converting them into a Java Class instance.
A Java program, isn't a single executable file, but is composed of many individual class files containing the platform-independent byte code. During execution, classes are not loaded into JVM memory all at once, but based on demand, as needed by the program – this is where the ClassLoaders come into picture. A classloader is a subclass of the java.lang.ClassLoader class. Each classloader, in turn, is designed to work with one or more codesources. A codesource is a root location from which the JVM searches for classes. Codesources can be defined to represent physical storage of binary class files, URLs, or even classes generated on the fly.
Typically class loaders are arranged in a parent/child hierarchy. When a class loading request is presented to a class loader, it first asks its parent class loader to fulfill the request. The parent, in turn, asks its parent for the class until the request reaches the top of the hierarchy. If the class loader at the top of the hierarchy cannot fulfill the request, then the child class loader that called it is responsible for loading the class. If the child is also unable to load the class, the request continues back down the hierarchy until a class loader fulfills it or a ClassNotFoundException is produced by the class loader at the bottom of the hierarchy.
The Process of ClassLoading in Java environment
When a JVM is started, it forms an initial classloader hierarchy composed of three loaders:
- The bootstrap (also known as “primordial”) loader is responsible for loading the core Java classes (rt.jar & i18n.jar). This “loader” is unique in that it is not actually a subclass of java.lang.ClassLoader but is implemented by the JVM itself.
- The extension loads classes from the jars in the JRE's extension directory (jre/lib/ext). This provides a standard mechanism to introduce new functionality beyond the core Java classes. Calling getParent() on this instance will always return null, since the bootstrap loader is not an actual ClassLoader instance.
- The system loader is responsible for loading classes from the directories and jars listed on the command-line (-cp/-classpath) and/or the java.class.path and CLASSPATH system properties. If not otherwise specified, any user instantiated ClassLoader will have this loader as its parent.
- The user defined ClassLoader allows applications to customize class loading as per their needs
Phases of Class Loading
The entire class loading process can essentially be broken down into three phases-
Loading
- Locating the required class file and loading the bytecode
- Gives a very basic memory structure to the class object. Methods, fields, and other referenced classes. A notable point here is that the referenced classes are not dealt with at this stage therefore, the class is not usable
Linking
- Bytecode verification - The class loader does a number of checks on the bytecodes
- Class preparation - Prepares the necessary data structures that represent fields, methods, and implemented interfaces that are defined within classes
- Resolving – Loads all the other referenced classes (Superclasses, Interface, Fields, Method signature, Local variables)
Initialization – any static initializes contained within a class are executed
Explicit v/s Implicit Class Loading
cl.loadClass() - where cl is an instance of java.lang.ClassLoader)
Class.forName() - the starting class loader is the defining class loader of the current class
If the Class whose name is specified is already loaded, classloader returns the reference to it from cache. Otherwise loader goes through the delegation model to load the class.
Implicit class loading occurs when the class is loaded as a result of reference, inheritance or initialization. Again, class is either returned from cache or through the delegation model.
Classes are often loaded through a combination of explicit and implicit class loading. For example, a class loader could first load a class explicitly and then load all of its referenced classes implicitly.
The Need For Your Own Class loader:
Following are some of the catalysts-
- To allow class loading from alternative repositories – Load classes that are not in the classpath - over the network, out of a database, from Java source code, out of a plug-in directory, or generate them on the fly
- Selectively load a specific version – All application developers to check for update and selectively load classes from specific locations (jar/zip/folder).
- To allow the unloading of classes – This case is useful if the application creates large numbers of classes that are used for only a finite period. Because a class loader maintains a cache of the classes that it has loaded, these classes cannot be unloaded until the class loader itself has been de-referenced. For this reason, system and extension classes are never unloaded, but application classes can be unloaded when their classloader is.
- Security – Your ClassLoader could examine classes before they are handed off to the JVM to see if they have a proper digital signature.
- Encryption – It's possible to create a ClassLoader that decrypts on the fly, so that your class files on disk are not readable by someone with a decompiler.
- Archiving – Want to distribute your code in a special format or with special compression? Your ClassLoader can pull raw class file bytes from any source it wants.
Common Class Loading Issues
Thrown when an application tries to explicitly load a class using class name string and class (.class file) is not found in the classpath
Can be easily checked by enabling –verbose:class JVM argument
NoClassDefFoundError
Thrown if the ClassLoader instance tries to implicitly load in the definition of a class and no definition of the class could be found.
ClassCastException
Thrown as a result of incompatible types being found in a type comparison. It indicates that the code has attempted to cast an object to a subclass of which it is not an instance. (remember ClassLoader Namespace)
Two classes of the same fully qualified name are not equal to each other if they are loaded by different ClassLoaders. They cannot be cast to each other and such operations would result in a ClassCastException