Java Class Loaders

Java Language Specification (JLS) speaks about Java Class Loaders, and If understood properly, It helps programmers get rid of Debug and save their time.

When we say, Java loads any class, we mean that instances java.lang.ClassLoader loads that class. This class can be extended, to create your custom class loaders.

When You execute a simple Class,
1. Bootstrap loader is responsible to have already loaded Key Java Classes like java.lang.Object
2. Ext loader is responsible for loading java extensions
3. Class Loader is responsible for loading the class that you want to execute.

The parent class loader for any class loader is the class loader instance that loaded that class loader.

To set the parent class loader:

public class CustomClassLoader extends ClassLoader{
public CustomClassLoader(){
super(CustomClassLoader.class.getClassLoader());
}
}


Note: If we have one class HelloWorld.java and two custom class loaders, CustomLoader1 and CustomLoader2, then HelloWorld would be executed twice and both the instances of HelloWorld are not equal.

i.e. HelloWorld hw1 = (HelloWorld) hw2; //throws ClassCastException


Who should write custom class loaders?

Those who wish to control JVM's classloading or do not like the default behavior of classloader. i.e. If HelloWorld is such a class that changes so rapidly and on the fly, we need to make sure it is loaded each time it is changed, since default Java loader never reloads any class. Your class loader should know that the class has changed.


import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
public class CustomClassLoader extends ClassLoader {
public CustomClassLoader(){
super(CustomClassLoader.class.getClassLoader());
}

public Class loadClass(String className) throws ClassNotFoundException {
return findClass(className);
}

public Class findClass(String className){
byte classByte[];
Class result=null;
result = (Class)classes.get(className);
if(result != null){
return result;
}

try{
return findSystemClass(className);
}catch(Exception e){
}
try{
String classPath = ((String)ClassLoader.getSystemResource(className.replace('.',File.separatorChar)+".class").getFile()).substring(1);
classByte = loadClassData(classPath);
result = defineClass(className,classByte,0,classByte.length,null);
classes.put(className,result);
return result;
}catch(Exception e){
return null;
}
}

private byte[] loadClassData(String className) throws IOException{

File f ;
f = new File(className);
int size = (int)f.length();
byte buff[] = new byte[size];
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buff);
dis.close();
return buff;
}

private Hashtable classes = new Hashtable();
}


Here is how to use the CustomClassLoader.

public class CustomClassLoaderTest {

public static void main(String [] args) throws Exception{
CustomClassLoader test = new CustomClassLoader();
test.loadClass( com.test.HelloWorld );
}
}


So, This is the sequence of Class Loaders.
  1. Bootstrap classes: the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.
  2. Installed extensions: classes in JAR files in the lib/ext directory of the JRE, and in the system-wide, platform-specific extension directory (such as /usr/jdk/packages/lib/ext on the SolarisTM Operating System, but note that use of this directory applies only to JavaTM 6 and later).
  3. The class path: classes, including classes in JAR files, on paths specified by the system property java.class.path. If a JAR file on the class path has a manifest with the Class-Path attribute, JAR files specified by the Class-Path attribute will be searched also. By default, the java.class.path property's value is ., the current directory. You can change the value by using the -classpath or -cp command-line options, or setting the CLASSPATH environment variable. The command-line options override the setting of the CLASSPATH environment variable.
Here is the Overall Mechanism
  • Constructors in java.lang.ClassLoader and its subclasses allow you to specify a parent when you instantiate a new class loader. If you don't explicitly specify a parent, the virtual machine's system class loader will be assigned as the default parent.
  • The loadClass method in ClassLoader performs these tasks, in order, when called to load a class:
    1. If a class has already been loaded, it returns it.
    2. Otherwise, it delegates the search for the new class to the parent class loader.
    3. If the parent class loader does not find the class, loadClass calls the method findClass to find and load the class.
  • The findClass method of ClassLoader searches for the class in the current class loader if the class wasn't found by the parent class loader. You will probably want to override this method when you instantiate a class loader subclass in your application.
  • The class java.net.URLClassLoader serves as the basic class loader for extensions and other JAR files, overriding the findClass method of java.lang.ClassLoader to search one or more specified URLs for classes and resources.

Comments