Today, I've read about class loaders. Sort of interesting. Similar to our inheritance heirachy and most of the stuff is working as we think how it could be.
The
Class loader concept, one of the cornerstones of the Java virtual
machine, describes the behavior of converting a named class into the
bits responsible for implementing that class. Because class loaders
exist, the Java run time does not need to know anything about files and
file systems when running Java programs.
Class loaders are
hierarchical. Classes are introduced into the JVM as they are referenced
by name in a class that is already running in the JVM. So how is the
very first class loaded? The very first class is specially loaded with
the help of static main() method declared in your class. All the
subsequently loaded classes are loaded by the classes, which are already
loaded and running. A class loader creates a namespace. All JVMs
include at least one class loader that is embedded within the JVM called
the primordial (or bootstrap) class loader. It is somewhat special
because the virtual machine assumes that it has access to a repository
of trusted classes which can be run by the VM without verification.
When
a new JVM instance is started , the bootstrap class loader is
responsible for loading key java classes like java.lang.Object and other
runtime code into memory. The runtime classes are packaged inside
jre/lib/rt.jar file. We cannot find the details of the bootstrap class
loader in the java language specification, since this is a native
implementation. For this reason the behavior of the bootstrap class
loader will differ across JVMs.
Java can change its class storage model simply by changing the set of functions that implements the class loader.
Now
let’s look at non-primordial class loaders. The JVM has hooks in it to
allow user defined class loaders to be used in place of primordial class
loader.
ex : Bootstrap (primordial) Loads JDK internal classes,
java.* packages. (as defined in the sun.boot.class.path system
property, typically loads rt.jar and i18n.jar) and is the parent in the
Class loaders hierarchy.
next comes the Extensions (Loads jar
files from JDK extensions directory (as defined in the java.ext.dirs
system property – usually lib/ext directory of the JRE) and then System
(Loads classes from system classpath (as defined by the java.class.path
property, which is set by the CLASSPATH environment variable or
–classpath or –cp command line options) ClassLoaders.
Classes
loaded by Bootstrap class loader have no visibility into classes loaded
by its descendants (ie Extensions and Systems class loaders).
The
classes loaded by system class loader have visibility into classes
loaded by its parents (ie Extensions and Bootstrap class loaders).
If
there were any sibling class loaders they cannot see classes loaded by
each other. They can only see the classes loaded by their parent class
loader. For example Sibling1 class loader cannot see classes loaded by
Sibling2 class loader
Both
Sibling1 and Sibling2 class loaders have visibilty into classes loaded
by their parent class loaders (eg: System, Extensions, and Bootstrap)
Class
loaders are hierarchical and use a delegation model when loading a
class. Class loaders request their parent to load the class first before
attempting to load it themselves. When a class loader loads a class,
the child class loaders in the hierarchy will never reload the class
again. Hence uniqueness is maintained. Classes loaded by a child class
loader have visibility into classes loaded by its parents up the
hierarchy but the reverse is not true
Note : Two objects
loaded by different class loaders are never equal even if they carry the
same values, which mean a class is uniquely identified in the context
of the associated class loader. This applies to singletons too, where
each class loader will have its own singleton.
At its simplest, a
class loader creates a flat name space of class bodies that are
referenced by a string name. The method definition is:
Class r = loadClass(String className, boolean resolveIt);
The
variable className contains a string that is understood by the class
loader and is used to uniquely identify a class implementation. The
variable resolveIt is a flag to tell the class loader that classes
referenced by this class name should be resolved (that is, any
referenced class should be loaded as well).
We can build our own
ClassLoader by being a subclass of java.lang.ClassLoader. The only
abstract method that must be implemented is loadClass().
Static Class Loading :
Classes are statically loaded with Java’s 'new' operator.
class MyClass {
public static void main(String args[]) {
Car c = new Car();
}
}
A
NoClassDefFoundException is thrown if a class is referenced with Java’s
'new' operator (i.e. static loading) but the runtime system cannot find
the referenced class.
Dynamic class loading:
Dynamic loading is a technique for programmatically invoking the functions of a class loader at run time.
we can load classes dynamically by...
Class.forName (String className); //static method which returns a Class
The
above static method returns the class object associated with the class
name. The string className can be supplied dynamically at run time.
Unlike the static loading, the dynamic loading will decide whether to
load the class Car or the class Jeep at runtime based on a properties
file and/or other runtime conditions. Once the class is dynamically
loaded the following method returns an instance of the loaded class.
It’s just like creating a class object with no arguments.
class.newInstance (); //A non-static method, which creates an instance of a class (i.e. creates an object).
Jeep myJeep = null ;
//myClassName should be read from a properties file or Constants interface.
//stay away from hard coding values in your program.
String myClassName = "au.com.Jeep" ;
Class vehicleClass = Class.forName(myClassName) ;
myJeep = (Jeep) vehicleClass.newInstance();
myJeep.setFuelCapacity(50);
A
ClassNotFoundException is thrown when an application tries to load in a
class through its string name using the following methods but no
definition for the class with the specified name could be found:
1. The forName(..) method in class - Class.
2. The findSystemClass(..) method in class - ClassLoader.
3. The loadClass(..) method in class - ClassLoader.
The
Java virtual machine has hooks in it to allow a user-defined class
loader to be used in place of the primordial one. Furthermore, since the
user class loader gets first crack at the class name, the user is able
to implement any number of interesting class repositories, not the least
of which is HTTP servers -- which got Java off the ground in the first
place.
There is a cost, however, because the class loader is so
powerful (for example, it can replace java.lang.Object with its own
version), Java classes like applets are not allowed to instantiate their
own loaders. (This is enforced by the class loader, by the way.) This
column will not be useful if you are trying to do this stuff with an
applet, only with an application running from the trusted class
repository (such as local files).
Java class loaders can be broadly classified into below categories:
- Bootstrap Class Loader
Bootstrap class loader loads java’s core classes like java.lang,
java.util etc. These are classes that are part of java runtime
environment. Bootstrap class loader is native implementation and so they
may differ across different JVMs.
- Extensions Class Loader
JAVA_HOME/jre/lib/ext contains jar packages that are extensions of
standard core java classes. Extensions class loader loads classes from
this ext folder. Using the system environment propery java.ext.dirs you
can add ‘ext’ folders and jar files to be loaded using extensions class
loader.
- System Class Loader
Java classes that are available in the java classpath are loaded using System class loader.
You can see more class loaders like java.net.URLClassLoader,
java.security.SecureClassLoader etc. Those are all extended from
java.lang.ClassLoader