Overview

Java class loaders are used to load classes at runtime. Dynamical class loading was designed originally for Applets loading. ClassLoader in Java works on three principle: delegation, visibility and uniqueness. Class loaders are defined hierarchically and each class loader has a delegation parent. The delegation defines a search order for binary class representations.

  • delegation
    • only try to load the class if the parent classloader can not load it
  • visibility
    • child class loader to see all the classes loaded by parent ClassLoader, but parent class loader can not see classes loaded by child
  • uniqueness
    • one classloader only loads the class once

Every class loader has a predefined location, from where they loads class files. There are three classloaders provided by the JRE: Bootstrap, Extension and Application ClassLoader.

  • Bootstrap ClassLoader

    • load JRE/lib/rt.jar
    • null parent
  • Extension ClassLoader

    • load JRE/lib/ext or any directory denoted by java.ext.dirs
    • null parent => use bootstrap loader
  • Application ClassLoader

    • load from CLASSPATH environment variable, -classpath or -cp option, Class-Path attribute of Manifest inside JAR file
    • parent is Extension ClassLoader

Except the bootstrap loader, all classloaders derive from java.lang.ClassLoader. Source code of ClassLoader's loadClass() method

    protected synchronized Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        // First, check if the class has already been loaded
        Class c = findLoadedClass(name); // calls JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name), use this loader and full class name to identify a class 
        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;
    }

Here are some highlights of the class-loading API:

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:

  • If a class has already been loaded, it returns it. Otherwise, it delegates the search for the new class to the parent class loader.
  • 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.

There are two classloaders associated with a class:

  • initiating loader

    • the classloader that calls its loadClass() method
  • defining loader

    • the classloader that ends up calling defineClass(), which is a final method that constructs a Class object from byte array.

Because of the delegation machanism, a loaded class is uniquely identified by its name and its defining classloader. So here comes the question: Can a same class file from a same location be loaded twice? If delegation principle holds, two custom classloader can load a same class twice if they are the defining loaders, but if they delegate the loading to a same parent loader, this cannot happen.

Note that to write your own custom classloader, you can either override findClass() or loadClass(). The ClassLoader's findClass() does not do anything and expects the subclass to override it. The ClassLoader's loadClass() implemented the delegation machanism, this method gets overriden means delegation could be violated, the subclass can implement it anyway it wants. In this case, the child loader can even load a class that is already loaded by its parent loader.

Reference

results matching ""

    No results matching ""