Java ClassLoader Example
In this article, we’re going to discuss different types of Java ClassLoader, how they work and some examples to build our own implementation.
1. Introduction
A class loader is an object that is responsible for loading classes. The ClassLoader class is an abstract class that uses a delegation model to search for classes and resources.
Furthermore, the ClassLoader is part of JRE (Java Runtime Environment) that dynamically loads Java classes into the JVM (Java Virtual Machine).
In Java, there is three different types of class loader:
- Bootstrap ClassLoader
- Extension ClassLoader
- System ClassLoader
In the next sections, we are going to understand how class loader works and see a custom example.
2.Pre-requisites
The minimum Java version for executing the article’s example is JDK 8 (find here), but we can use the most recently released Java version (JDK 15).
Also, I’m using IntelliJ 2020.2, but you can use any IDE with support for versions recommended above.
3. Types of Class Loaders
3.1 Bootstrap ClassLoader
A Bootstrap ClassLoader is a native machine code which starts the operation when the JVM calls it. That is said, it might has different implementation between platforms.
It serves as a parent of all the other ClassLoader instances, but is not a Java class. Typically, it loads the rt.jar
and other core Java libraries.
3.2 Extension ClassLoader
The Extension ClassLoader is a child of Bootstrap ClassLoader. It takes care of loading the extensions of the standard core Java classes, making them available to all applications running on the platform.
It’s also responsible to load files from $JAVA_HOME/lib/ext directory or any other directory mentioned in the java.ext.dirs system property.
3.3 System ClassLoader
The System or Application ClassLoader takes care of loading all the application level classes into the JVM.
It loads the Application type classes found in the environment variable CLASSPATH, -classpath or -cp command line option. Besides, it’s a child of Extension ClassLoader.
4. How ClassLoader works
The process of ClassLoader works like that:
- JVM requests a class.
- ClassLoader tries to locate the class using fully qualified class name.
- ClassLoader loads into runtime the found class.
In case of ClassLoader doesn’t find the required class, it delegates the request to the parent class loader.
Eventually, if the parent class loader doesn’t find the class, then the child class will call java.net.URLClassLoader.findClass()
method to look for classes in the file system itself.
Finally, if the child class isn’t able to find the class, a java.lang.NoClassDefFoundError or java.lang.ClassNotFoundException is threw.
Here is an example of ClassNotFoundException output:
ClassNotFoundException example
java.lang.ClassNotFoundException: com.example.javacodegeeks.ExampleClassLoader at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348)
Above, we can observe the sequence of event told before starting with parent class trying to load the class java.net.URLClassLoader.findClass()
look for the class itself.
In the end, if the class is not loaded it throws ClassNotFoundException.
There are three important features of ClassLoader that we’ll see below.
4.1 Delegation Model
Delegation Hierarchy Algorithm is used in JVM and Java ClassLoader to load the classes into the Java file.
For instance, let’s say we want to load an application class to JVM. The system class loader first delegates to its parent extension class loader which in turn delegates it to the bootstrap class loader.
Only if the bootstrap and then the extension class loader is unsuccessful in loading the class, the system class loader tries to load the class itself.
4.2 Visibility principle
The Visibility Principle states that a class loaded by a parent ClassLoader is visible to the child ClassLoaders but a class loaded by a child ClassLoader is not visible to the parent ClassLoaders.
Suppose that if Class A is loaded by an application class loader and class B is loaded by the extensions class loader, then both A and B classes are visible as far as other classes loaded by an Application class loader are concerned.
That said, when a class has been loaded by the Extension ClassLoader, then that class is only visible to the Extension ClassLoader and Application ClassLoader but not to the Bootstrap ClassLoader.
If that class is again tried to load using Bootstrap ClassLoader, we get an exception java.lang.ClassNotFoundException.
4.3 Unique property
The Unique (or Uniqueness) Property says that the classes are unique and there is no repetition of classes.
If the parent class loader isn’t able to find the class, only then the current instance would attempt to do so itself.
5. Custom ClassLoader
In the below example, we defined a custom class loader that extends the default class loader and loads a byte array from the specified file.
CustomClassLoader.java
public class CustomClassLoader extends ClassLoader { @Override public Class findClass(String name) throws ClassFormatError { byte[] b = loadClassFromFile(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassFromFile(String fileName) { InputStream inputStream = getClass().getClassLoader().getResourceAsStream( fileName.replace('.', File.separatorChar) + ".class"); byte[] buffer; ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); int nextValue = 0; try { while ( (nextValue = inputStream.read()) != -1 ) { byteStream.write(nextValue); } } catch (IOException e) { e.printStackTrace(); } buffer = byteStream.toByteArray(); return buffer; } }
We need to extend the ClassLoader
class and override the findClass()
method.
The findclass()
method finds the class with the fully qualified name as a parameter. We need to override this method in custom class loader implementations that follow the delegation model for loading classes.
To execute our example above, we create this main class:
ExampleClassLoaderMain.java
public class ExampleClassLoaderMain { public static void main(String[] args) { CustomClassLoader customClassLoader = new CustomClassLoader(); try { Object obj; obj = customClassLoader.findClass("com.example.javacodegeeks.classloaderexample.Character").newInstance(); Method[] methods = obj.getClass().getDeclaredMethods(); System.out.println(String.format("Methods of %s class:",obj.getClass().getName())); for(Method method : methods) { System.out.println(method.getName()); } } catch (ClassFormatError e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } }
The output is a print of Character
class methods.
Example’s output
Methods of com.example.javacodegeeks.classloaderexample.Character class: getAge setAge getWeight setWeight getHeight setHeight getName setName
6. Summary
In conclusion, we take a look on how ClassLoader works in Java. Further, we saw the type of class loaders and made an example implementation to see how we could use this important component of Java environment in our applications.
7. Download the source code
You can download the full source code of this example here: Java ClassLoader Example