Inside the class loader
The class loader is a fundamental part of Java that people tend to know less about. Usually it's a cog that quietly turns in the background and gives you no trouble. It's all the worse when the cog gets stuck. Knowing how class loaders work is useful, and if you write web or enterprise applications it's essential.
A class loader (the abstract class java.lang.ClassLoader), as its name suggests, is responsible for loading classes. If you're wondering why we need a class loader and why Java doesn't just do it automatically, the answer is that it does. Applications have different needs, though. Think of an application server that has to deploy applications while it's running. A class loader can meet requirements like dynamically loading classes while an application is running.
Another use for class loaders is loading classes from different sources, such as a disk, a network or a database. That's why java.lang.ClassLoader defines the method defineClass, which receives the class definition as an array of bytes.
The JVM ensures that once a class is loaded it won't be loaded again. Within the JVM each class is identified by its fully qualified name, meaning the package and class name, and the class loader that loaded it. This matters. For example, if class loader C1 loads a class Foo in package hoo and class loader C2 loads a class Foo in package hoo, they're two different classes. Trying to cast their instances would give us a ClassCastException.
Historically, Java 1.1 used only the fully qualified class name as the identifier, without the class loader that loaded it. It soon turned out that this was not type-safe, because one class could be passed off as another. See the article Java is not type-safe.
The class loader hierarchy is a tree, which makes delegation possible. The hierarchy also limits class visibility to the space a class loader defines. In that space, a class loader can see classes it loaded itself or that one of its ancestors loaded. It cannot see classes loaded by any of its descendants. The parent-child relationship is about links between objects rather than inheritance.

- Bootstrap class loader — loads the core Java classes.
- Extension class loader — loads Java extensions from Java's extension directory.
- Classpath class loader — loads classes on the classpath.
- Custom class loader — can load classes from any source and in practically any way.
As mentioned above, the JVM has to ensure that a given class is loaded only once in a class loader's domain, which guarantees that its bytecode won't change over time. Java uses a parent-first delegation model for class loaders. A class loader first delegates loading to its parent and tries to load the class itself only if the parent doesn't find it.
Below is the code for the loadClass method from the class java.lang.ClassLoader
protected synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
Every rule has an exception. In the J2EE world this rule is turned on its head, even by the specification. Each application server has a hierarchy of class loaders. For Apache Tomcat it looks like this.
Bootstrap
|
System
|
Common
/ \
Catalina Shared
/ \
Webapp1 Webapp2
As the diagram shows, each web application has its own class loader. That loader looks for a class locally before delegating to the parent. The application can therefore have its own version of a class with the same qualified name as one already loaded by a parent. It's worth remembering here that java.lang.Thread defines the method setContextClassLoader, which lets you specify the class loader a thread should use when looking for classes.
Class loaders also make hot redeployment possible, meaning you can load a new version of an application without restarting it. The JVM won't let you repeatedly load the same class in the same class loader's space, but there's a little trick. You load the class again with a different class loader and set the original references to the class loader's classes to null. The garbage collector can then clean them up.
Class foo = Class.forName("Foo", false, newClassloader)Note: Unfortunately, Tomcat and by extension JBoss have an unpleasant bug where some references aren't cleared. Repeatedly redeploying an application on a running server therefore leads to an OutOfMemoryError in PermGen space. PermGen is the part of the heap, Java's memory store, that holds class and method definitions. The workaround is to restart the server periodically or enlarge that part of the JVM heap using -XX:MaxPermSize=velikost.
Class loaders are a fascinating subject whose details go beyond this article. In the J2EE world, for example, each application server has its own class loader configuration and behavior. The following links will help you find out more.
Related links
- Internals of Java Class Loading
- Inside Class Loaders
- Dynamic Class Loading in the JavaTM Virtual Machine (PDF)
- Advanced JBoss Class Loading
- Understanding the Java ClassLoader (PDF)
- Understanding J2EE Application Server Class Loading Architectures
- Tomcat Apache Classloader howto
- A Look At The Java Class Loader
Related articles
Related CZ Podcast episodes
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio