1. Class Loading in J2SE Environment
Java Class Loading mechanism is one of the darkest corners inside java virtual machine.
The class loading concept describes the behavior of converting a named class into the bits
responsible for implementing that class.
Wait a minute! “I never have to deal with it. Why do I need to know this bulky
philosophy”, this might flash in your mind. In that case, think of below-
ClassNotFoundException
NoClassDefFoundException
ClassCastException
Sounds familiar?
Most of the developers have had this frustrating experience trying to debug some of these
exceptions. Post Java2, class loading is no longer as simple as defining a CLASSPATH
environment variable. J2EE application servers supplement the CLASSPATH with many
different mechanisms. The Java ClassLoader is a crucial, but often overlooked,
component of the Java run-time system.
Okay, so what really a ClassLoader is?
Let’s start with the basics. A Java program, isn't a single executable file, but is composed
of many individual class files containing the platform-independent byte code. During
execution, classes are not loaded into JVM memory all at once, but based on demand, as
needed by the program – this is where the ClassLoaders come into picture. A classloader
is a subclass of the java.lang.ClassLoader class. Each classloader, in turn, is designed to
work with one or more codesources. A codesource is a root location from which the JVM
searches for classes. Codesources can be defined to represent physical storage of binary
class files, URLs, or even classes generated on the fly.
What is Class Loading?
The term "class loading" refers to the process of locating the bytes for a given class name
and converting them into a Java Class instance. All java.lang.Class instances within a
JVM start life as an array of bytes, structured in the class file format defined by the JVM
specification.
Class loading in J2SE environment
When a JVM is started (in all versions since JDK 1.2), it forms an initial classloader
hierarchy composed of three loaders:
The bootstrap (also known as “primordial”) loader is responsible for loading the
core Java classes (rt.jar & i18n.jar). This “loader” is unique in that it is not
actually a subclass of java.lang.ClassLoader but is implemented by the JVM
itself.
2. The extension loads classes from the
jars in the JRE's extension directory
(jre/lib/ext). This provides a standard
mechanism to introduce new
functionality beyond the core Java
classes. Calling getParent() on this
instance will always return null,
since the bootstrap loader is not an
actual ClassLoader instance.
The system loader is responsible for
loading classes from the directories
and jars listed on the command-line
(-cp/-classpath) and/or the
java.class.path and CLASSPATH
system properties. If not otherwise
specified, any user instantiated
ClassLoader will have this loader as
its parent.
The user defined ClassLoader
allows applications to customize
class loading as per their needs
Phases of Class Loading
The entire class loading process can essentially be broken down into three phases-
Loading
Locating the required class file and loading the bytecode
Gives a very basic memory structure to the class object. Methods, fields,
and other referenced classes. A notable point here is that the referenced
classes are not dealt with at this stage therefore, the class is not usable
Linking
Bytecode verification - The class loader does a number of checks on the
bytecodes
Class preparation - Prepares the necessary data structures that represent
fields, methods, and implemented interfaces that are defined within classes
Resolving – Loads all the other referenced classes (Superclasses,
Interface, Fields, Method signature, Local variables)
Initialization – any static initializes contained within a class are executed
3. Three Principles of ClassLoader Operation
Delegation Principal
According to this principle, if a particular class is not loaded already, the
classloaders delegate the requests to load that class to their parent
classloaders.
Since the System-Classpath classloader loaded the MyApp class, it first
asks its parent, the extension classloader to load the class. The extension
classloader asks the Bootstrap classloader to load java.util.Vector. Since
java.util.Vector is a J2SE class, the bootstrap classloader loads it and
returns.
4. In case MyApp creates new instance of MyClass, bootstrap & extension
classloaders cannot find the class. Finally the request comes back to
system classloader which finds the class and loads it.
Visibility Principal
According to this principle, Classes loaded by parent classloaders are
visible to child classloaders but not vice versa
For classes loaded by ClassLoader X, classes A, B and X are visible, but
not class Y. Sibling classloaders cannot see each other’s classes.
Uniqueness Principal
According to this principle, when a classloader loads a class, the child
classloaders in the hierarchy will never reload the class. This follows from
the delegation principle since a classloader always delegates class loading
to its parents. The child classloader will load it (or try to load it) only if the
parent hierarchy fails to load the class. Thus the uniqueness of the class is
maintained. An interesting scenario emerges when both parent and child
classloaders load the same
5. ClassLoader Namespaces
• Each classloader (or instance of a ClassLoader subclass) defines a unique and
separate namespace.
• For a given class with name N, only one instance of class N may exist within a
given classloader. But the same class can be loaded by two different classloaders
• JVM considers each class to be further qualified by the ClassLoader instance that
loaded it. In effect, the full name of a class consists of its fully qualified class
name plus its classloader
• If two different classloaders load com.test.cl.vo.B, there will be two Class
instances, each with its own separate static data. Any attempt to cast an object
from one to the other will result in a ClassCastException
• So, your singleton is per classloader hierarchy than the JVM
How to access a ClassLoader
• class.getClassLoader()
• classLoader.getSystemClassLoader()
• Thread.currentThread().getContextClassLoader()
• An application specific method to retrieve a classloader
6. In all the cases initial loader selection is critical because it defines the visibility.
Explicit v/s Implicit Class Loading
Explicit class loading occurs when class is loaded using one of the following
method
cl.loadClass() - where cl is an instance of java.lang.ClassLoader)
Class.forName() - the starting class loader is the defining class loader of
the current class
If the Class whose name is specified is already loaded, classloader returns the
reference to it from cache. Otherwise loader goes through the delegation model to
load the class.
Implicit class loading occurs when the class is loaded as a result of reference,
inheritance or initialization. Again, class is either returned from cache or through
the delegation model.
Classes are often loaded through a combination of explicit and implicit class
loading. For example, a class loader could first load a class explicitly and then
load all of its referenced classes implicitly.
Why to write a custom class loader?
Following are some of the catalysts-
• To allow class loading from alternative repositories – Load classes that are not
in the classpath - over the network, out of a database, from Java source code, out
of a plug-in directory, or generate them on the fly
• Selectively load a specific version – All application developers to check for
update and selectively load classes from specific locations (jar/zip/folder).
• To allow the unloading of classes – This case is useful if the application creates
large numbers of classes that are used for only a finite period. Because a class
loader maintains a cache of the classes that it has loaded, these classes cannot be
unloaded until the class loader itself has been de-referenced. For this reason,
system and extension classes are never unloaded, but application classes can be
unloaded when their classloader is.
• Security – Your ClassLoader could examine classes before they are handed off to
the JVM to see if they have a proper digital signature.
• Encryption – It's possible to create a ClassLoader that decrypts on the fly, so that
your class files on disk are not readable by someone with a decompiler.
• Archiving – Want to distribute your code in a special format or with special
compression? Your ClassLoader can pull raw class file bytes from any source it
wants.
7. Common Class Loading Issues
ClassNotFoundException
Thrown when an application tries to explicitly load a class using class
name string and class (.class file) is not found in the classpath
Can be easily checked by enabling –verbose:class JVM argument
NoClassDefFoundError
Thrown if the ClassLoader instance tries to implicitly load in the definition
of a class and no definition of the class could be found.
ClassCastException
Thrown as a result of incompatible types being found in a type
comparison. It indicates that the code has attempted to cast an object to a
subclass of which it is not an instance. (remember ClassLoader
Namespace)
Two classes of the same fully qualified name are not equal to each other if
they are loaded by different ClassLoaders. They cannot be cast to each
other and such operations would result in a ClassCastException
Class Loading Options
Following Table summarizes the command-line options for setting the classpaths of the
three standard class loaders:
Class loader
Command-line option Explanation
involved
-Xbootclasspath:<directories and Sets the search path for
Bootstrap
zip/JAR files separated by ; or : bootstrap classes and resources.
-Xbootclasspath/a:<directories and zip/ Appends the path to end of the
Bootstrap
JAR files separated by ; or : boot classpath.
-Xbootclasspath/p:<directories and zip/ Prefix the path to front of the
Bootstrap
JAR files separated by ; or : boot classpath.
-Djava.ext.dirs=<directories and Specifies the search path for the
Extension
zip/JAR files separated by ; or : extension classes and resources.
Sets the search path for
-cp or -classpath <directories and
application classes and System
zip/JAR files separated by ; or :
resources.
Sets the search path for
-Djava.class.path=<directories and zip/
application classes and System
JAR files separated by ; or :
resources.