Are you thinking of writing ClassLoaders? or are you facing "unexpected" ClassCastException or LinkageError with wierd message "loader constraint violation". Then, it is time to take a closer look at Java class loading process.
A Java class is loaded by an instance of java.lang.ClassLoader class. java.lang.ClassLoader itself is an abstract class and so a class loader can only an instance of a concrete subclass of java.lang.ClassLoader. If this is the case, which class loader loads java.lang.ClassLoader class itself? (classic "who will load the loader" bootstrap issue). It turns out that there is a bootstrap class loader built into the JVM. The bootstrap loader loads java.lang.ClassLoader and many other Java platform classes.
To load a specific Java class, say for example com.acme.Foo, JVM invokes loadClass method of a java.lang.ClassLoader (actually, JVM looks for loadClassInternal method - if found it uses that method, or else JVM uses loadClass. And loadClassInternal method calls loadClass). loadClass receives name of the class to load and returns java.lang.Class instance that represent the loaded class. Actually, loadClass method finds the actual bytes of .class file (or URL) and calls defineClass method to construct java.lang.Class out of the byte array. Loader on which loadClass is called is referred as initiating loader (i.e., JVM initiates loading using that loader). But, the initiating loader need not directly find the byte[] for class - instead it may delegate the class loading to another class loader (for example, to it's parent loader) - which itself may delegate to another loader and so on. Eventually some class loader object in delegation chain ends up calling defineClass method to actually load the concerned class (com.acme.Foo). That particular loader is called defining loader of com.acme.Foo. At runtime, a Java class is uniquely identified by the pair - the fully qualified name of the class and the defining loader that loaded it. If the same named (i.e., same fully qualified name) class is defined by two different loaders, these classes are different - even if the .class bytes are same and loaded from the same location (URL).
Even with a good old simple "hello world" Java program, there are atleast 3 class loaders.
Let us assume you are running a "hello world" java program. We will how class loading proceeds. JVM loads main class using the "application class loader". If you run the following program
class Main {
public static void main(String[] args) {
System.out.println(Main.class.getClassLoader());
javax.swing.JFrame f = new javax.swing.JFrame();
f.setVisible(true);
SomeAppClass s = new SomeAppClass();
}
}
it prints something like
sun.misc.Launcher$AppClassLoader@17943a4
Whenever a reference to some other class has to be resolved from Main class, then JVM uses the defining loader of Main class - the application class loader - as initiating loader. In the above example, to load the class javax.swing.JFrame, JVM will use the application class loader as initiating loader. i.e., JVM will call loadClass() (loadClassInternal) on the application class loader. The application class loader delegates that to extension class loader. And the extension class loader checks whether it is a bootstrap class (using a private method - ClassLoader.findBootstrapClass) and the bootstrap loader defines the class by loading it from rt.jar. When reference to SomeAppClass has to be resolved, JVM follows the same process - it uses application class loader as initiating loader for it. The application loader delegates it to extension loader. Extension loader checks with bootstrap loader. Bootstrap loader won't find "SomeAppClass". Then extension loader checks whether "SomeAppClass" is in any of the extension jars and it won't find any. Then application class loader check the .class bytes in application CLASSPATH. If it finds, it defines the same. If not, NoClassDefFoundError will be thrown.
Stay tuned for more discussion on loader constraints and LinkageErrors..
To be continued...