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();
}
}
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..