Java Class Loading Mechanism
Class loading is one of the most powerful mechanisms provided by
the Java language specification.
Whenever we compile any Java file, the compiler will embed a
public, static, final field named
class
, of the type java.lang.Class
, in the
resultant byte code. Since this field is static, we can access this field using
class name like this:
Java.lang.Class kClass = MyClass.class;
When the run time environment needs to load a new class for an
application, it looks for the class in the following locations, in
order:
1. Bootstrap
classes: the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.
2. Installed
extensions : classes in JAR files in the
lib/ext directory of the JRE
3. The class path : classes, including classes
in JAR files, on paths specified by the system property java.class.path
The precedence list tells you, for example, that the class
path is searched only if a class to be loaded hasn't been found among the
classes in rt.jar, i18n.jar or the installed extensions.
The class in java is loaded by some class loader
instance. How class loader works? Once a
class is loaded in JVM, the same class will not be loaded again. How?
In Java, a class is identified by its fully qualified class name. The
fully qualified class name consists of the package name and the class name. But
in JVM, a class is uniquely identified using fully qualified class name along
with the instance of the ClassLoader that loaded the class in JVM.
Thus, if a class named
Cl
in the package Pkg
is loaded by an instance kl1
of the class loader KlassLoader
, the class
instance (java.lang.Class instance inserted
by compiler)
of C1
, i.e. C1.class
is keyed in the JVM as (Cl, Pkg,
kl1). So what if multiple instances (Kl1, Kl2, Kl3) of
class Loader say KlassLoader, loads the same class? How many class loader
instances do we have in a JVM? This is explained below.
Class Loaders
In
a JVM, each and every class is loaded by some instance of java.lang.ClassLoader
class. The ClassLoader is part of java.lang package and developers are free to
subclass java.lang.ClassLoader class and add their own functionality of class
loading.
When the JVM is started, three class loaders are used:
1.
Bootstrap
class Loader
Whenever a JVM is started by typing command
in command prompt like “java MyClass” (MyClass is an example class) or whenever
class is run through any IDE, the “Bootstrap class loader” is responsible for
loading the key classes like “java.lang.Object” and other runtime code
(java.lang.String, java.lang.* pkg etc) packaged in to jre/lib/rt.jar,
internationalization
classes in i18n.jar into memory
first. rt.jar contains packages like :
java.lang.*,
java.math.*,
java.io.*,
java.sql.*,
java.nio.*,
java.awt.*,
java.rmi.*,
javax.annotation.*,
javax.lang.
model.*
javax.rmi.*
etc.
Bootstrap class loader is a native
implementation and thus the behavior of the bootstrap class loader will also
vary across JVMs.
If we try to get the class loader of the core
java run time class like java.lang.String, we will get null, like this: log (java.lang.String.class.getClassLoader());
2.
Extension
class loader:
Extension libraries provide features beyond
core Java run time code.
The extension mechanism provides
a standard, scalable way to make custom APIs available to all applications
running on the Java platform.
An extension library acts as “add-on” modules to the Java platform
or Java core API. The
extension mechanism enables the run time environment to find and load extension
classes without the extension classes having to be named on the class path. These
extension libraries are normally placed in jre/lib/ext folder.
Developers can write their own
extension libraries and can place these libraries under jre/lib/ext folder and
these libraries are loaded same as java runtime classes without using class path. Since this mechanism extends the
platform's core API, its use should be judiciously applied.
Thus
extension libraries provide features beyond the core Java runtime code.
A
developer can add his or her own application .jar files or whatever libraries
he or she might need to add to the classpath to this extension directory so
that they will be loaded by the extension class loader.
Thus
extension class loader (
ExtClassLoader
class
) is responsible for loading all
.jar files under ext (most probably jre/lib/ext) folder.
3.
Application
Class Loader
The third and most important class loader
from the developer perspective is the
AppClassLoader
.
The application class loader is responsible for loading all of the classes kept
in the class path corresponding to the java.class.path
system property.
Above three class loaders are used
mostly. There are few more class loaders
in JDL like:
java.net.URLClassLoader
java.security.SecureClassLoader
java.rmi.server.RMIClassLoader
sun.applet.AppletClassLoader
How class Loaders
work:
Below points are very important for the correct working of
any class loader written by developers:-
1. All class loaders except bootstrap class loader
have a parent class loader.
2. All class loaders are of the type
java.lang.ClassLoader.
3. Class loaders should (practically: must)
delegate the loading of a class to the parent, but a custom class loader can
define for itself when it should do so.
4. A class is defined by its class type and the
class loader that has actually loaded the class.
5. A class is only loaded once and then cached in
the class loader to ensure that the byte code cannot change.
The parent class loader for any class loader is the class
loader instance that loaded the class loader. (Remember, a class loader is
itself a class). The most important aspect is to correctly set the parent class
loader. See below code snippet to set the parent class loader in a developer
written class loader.
public
class MyClassLoader extends ClassLoader{
public MyClassLoader(){
super(MyClassLoader.class.getClassLoader());
}
}
A class is requested out of class loader using the
loadClass() method of java.lang.ClassLoader class. Look below code snippet of
loadClass() method.
protected
synchronized Class<?> loadClass(String name, boolean resolve) throws
ClassNotFoundException
{
// First check if the class is already
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 to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
1. This method first checks if class is already
loaded using findLoadedClass() method.
22. If class loader instance that invoked this
method can’t find the class, and if parent (parent class loader) is set
correctly, it would ask the parent class loader first to load the class.
33. If the parent
cannot find it (which again means that its parent also cannot find the class,
and so on), and if the
findBootstrapClass0()
method also fails, the findClass()
method is invoked. The default implementation of findClass()
will throw ClassNotFoundException
as shown below:
protected
Class<?> findClass(String name)throws ClassNotFoundException
{
throw new ClassNotFoundException(name);
}
4. Developers are
expected to implement
findClass() method when they subclass java.lang.ClassLoader to
make custom class loader. Inside the findClass() method, the class loader needs
to fetch the byte codes from arbitrary source. The source can be the file system,database, network URL etc.
5. Once the byte code is retrieved, the findClass() method should
call the defineClass() method and runtime is very particular about which class
loader instance calls this method.
Note:
If two class loader instances define the byte codes from same or different
sources, the defined classes are different.
Below diagram explains the class loading mechanism using custom
class loaders, how many class loader instances we have in JVM and what would be
the impact of multiple instances of class loaders.
Explanation:--
1. Main class is MyMainClass.Java
2. As explained earlier, MyMainClass.class will
be loaded by AppClassLoader as AppClassLoader is responsible for loading
classes from class path.
3. MyMainClass creates instances of two class
loaders, CustomClassLoader1 and CustomClassLoader2, which are capable of
finding the byte code of 4th class named Target.class from some
source say a network path, which means Target.Java is not in the classpath and
hence is not loaded by AppClassLoader.
4. In this scenario, MyMainClass asks the custom class loaders
to load the target class, Target will be loaded and Target.class will be
defined independently by both CustomClassLoader1 and CustomClassLoader2
instances and this will lead to serious implications in Java like if Target
class has some static initialization code and if we want this code to be
executed only once in JVM, but in current scenario the static code will be
executed twice in the JVM: once each when class is loaded separately by both
custom class loaders CustomClassLoader1 and CustomClassLoader2 .
5. If the
Target class is instantiated in both the CustomClassLoaders to have instances
target1 and target2 as shown in above figure, then target1 and target2 are not
type compatible. JVM can’t execute the
below code snippet:
Target target3 = (Target) target2;
This will throw
ClassCastException because JVM sees these two as separate, distinct class types
since they are defined by different class loader instances.
The
above explanation holds true even if
MyMainClass
doesn't use two separate class loader classes like CustomClassLoader1
and CustomClassLoader2
, and instead uses two separate
instances of a single CustomClassLoader
class.
With
above we can conclude, In JVM we have single class loader instance to load the
class.