Sponsored Link •
The part of a Java virtual machine implementation that takes care of finding and loading types is the class loader subsystem. Chapter 1, "Introduction to Java's Architecture," gives an overview of this subsystem. Chapter 3, "Security," shows how the subsystem fits into Java's security model. This chapter describes the class loader subsystem in more detail and show how it relates to the other components of the virtual machine's internal architecture.
As mentioned in Chapter 1, the Java virtual machine contains two kinds of class loaders: a bootstrap class loader and user-defined class loaders. The bootstrap class loader is a part of the virtual machine implementation, and user-defined class loaders are part of the running Java application. Classes loaded by different class loaders are placed into separate name spaces inside the Java virtual machine.
The class loader subsystem involves many other parts of the Java virtual machine and several classes
java.lang library. For example, user-defined class loaders are regular Java
objects whose class descends from
java.lang.ClassLoader. The methods of
ClassLoader allow Java applications to access the virtual machine's class
loading machinery. Also, for every type a Java virtual machine loads, it creates an instance of class
java.lang.Class to represent that type. Like all objects, user-defined class loaders
and instances of class
Class reside on the heap. Data for loaded types resides in the
The class loader subsystem is responsible for more than just locating and importing the binary data for classes. It must also verify the correctness of imported classes, allocate and initialize memory for class variables, and assist in the resolution of symbolic references. These activities are performed in a strict order:
Java virtual machine implementations must be able to recognize and load classes and interfaces stored in binary files that conform to the Java class file format. An implementation is free to recognize other binary forms besides class files, but it must recognize class files.
Every Java virtual machine implementation has a bootstrap class loader, which knows how to load trusted classes, including the classes of the Java API. The Java virtual machine specification doesn't define how the bootstrap loader should locate classes. That is another decision the specification leaves to implementation designers.
Given a fully qualified type name, the bootstrap class loader must in some way attempt to
produce the data that defines the type. One common approach is demonstrated by the Java virtual machine
implementation in Sun's 1.1 JDK on Windows98. This implementation searches a user-defined directory
path stored in an environment variable named
CLASSPATH. The bootstrap loader looks
in each directory, in the order the directories appear in the
CLASSPATH, until it finds a
file with the appropriate name: the type's simple name plus "
.class". Unless the type
is part of the unnamed package, the bootstrap loader expects the file to be in a subdirectory of one the
directories in the
CLASSPATH. The path name of the subdirectory is built from the
package name of the type. For example, if the bootstrap class loader is searching for class
java.lang.Object, it will look for
Object.class in the
java\lang subdirectory of each
In 1.2, the bootstrap class loader of Sun's Java 2 SDK only looks in the directory in which the system
classes (the class files of the Java API) were installed. The bootstrap class loader of the implementation of
the Java virtual machine from Sun's Java 2 SDK does not look on the
Sun's Java 2 SDK virtual machine, searching the class path is the job of the system class
loader, a user-defined class loader that is created automatically when the virtual machine starts up.
More information on the class loading scheme of Sun's Java 2 SDK is given in Chapter 8, "The Linking
Although user-defined class loaders themselves are part of the Java application, four of the methods in
ClassLoader are gateways into the Java virtual machine:
// Four of the methods declared in class java.lang.ClassLoader: protected final Class defineClass(String name, byte data, int offset, int length); protected final Class defineClass(String name, byte data, int offset, int length, ProtectionDomain protectionDomain); protected final Class findSystemClass(String name); protected final void resolveClass(Class c);
Any Java virtual machine implementation must take care to connect these methods of class
ClassLoader to the internal class loader subsystem.
The two overloaded
defineClass() methods accept a
data, as input. Starting at position
offset in the array and continuing for
length bytes, class
ClassLoader expects binary data conforming to the Java class file format--binary
data that represents a new type for the running application -- with the fully qualified name specified in
name. The type is assigned to either a default protection domain, if the first version of
defineClass() is used, or to the protection domain object referenced by the
protectionDomain parameter. Every Java virtual machine implementation must
make sure the
defineClass() method of class
can cause a new type to be imported into the method area.
findSystemClass() method accepts a
representing a fully qualified name of a type. When a user-defined class loader invokes this method in
version 1.0 and 1.1, it is requesting that the virtual machine attempt to load the named type via its bootstrap
class loader. If the bootstrap class loader has already loaded or successfully loads the type, it returns a
reference to the
Class object representing the type. If it can't locate the binary data for
the type, it throws
ClassNotFoundException. In version 1.2, the
findSystemClass() method attempts to load the requested type from the system
class loader. Every Java virtual machine implementation must make sure the
findSystemClass() method can invoke the bootstrap (if version 1.0 or 1.1) or
system (if version 1.2 or later) class loader in this way.
resolveClass() method accepts a reference to a
Class instance. This method causes the type represented by the
Class instance to be linked (if it hasn't already been linked). The
defineClass() method, described previous, only takes care of loading. (See the
previous section, "Loading, Linking, and Initialization" for definitions of these terms.) When
defineClass() returns a
Class instance, the binary file for the
type has definitely been located and imported into the method area, but not necessarily linked and initialized.
Java virtual machine implementations make sure the
resolveClass() method of
ClassLoader can cause the class loader subsystem to perform linking.
The details of how a Java virtual machine performs class loading, linking, and initialization, with user- defined class loaders is given in Chapter 8, "The Linking Model."
As mentioned in Chapter 3, "Security," each class loader maintains its own name space populated by the types it has loaded. Because each class loader has its own name space, a single Java application can load multiple types with the same fully qualified name. A type's fully qualified name, therefore, is not always enough to uniquely identify it inside a Java virtual machine instance. If multiple types of that same name have been loaded into different name spaces, the identity of the class loader that loaded the type (the identity of the name space it is in) will also be needed to uniquely identify that type.
Name spaces arise inside a Java virtual machine instance as a result of the process of resolution. As part of the data for each loaded type, the Java virtual machine keeps track of the class loader that imported the type. When the virtual machine needs to resolve a symbolic reference from one class to another, it requests the referenced class from the same class loader that loaded the referencing class. This process is described in detail in Chapter 8, "The Linking Model."