Contents | Prev | Next | Index | The JavaTM Virtual Machine Specification |
CHAPTER 5
The Java virtual machine dynamically loads (§2.17.2), links (§2.17.3), and initializes
(§2.17.4) classes and interfaces. Loading is the process of finding the binary representation
of a class or interface type with a particular name and creating a class or
interface from that binary representation. Linking is the process of taking a class or
interface and combining it into the runtime state of the Java virtual machine so that it
can be executed. Initialization of a class or interface consists of executing the class or
interface initialization method <clinit>
(§3.9).
In this chapter, Section 5.1 describes how the Java virtual machine derives symbolic references from the binary representation of a class or interface. Section 5.2 explains how the processes of loading, linking, and initialization are first initiated by the Java virtual machine. Section 5.3 specifies how binary representations of classes and interfaces are loaded by class loaders and how classes and interfaces are created. Linking is described in Section 5.4. Section 5.5 details how classes and interfaces are initialized. Finally, Section 5.6 introduces the notion of binding native methods.
The constant_pool
table (§4.4) in the binary representation of a class or interface is used to construct the runtime constant pool upon class or interface creation (§5.3). All references in the runtime constant pool are initially symbolic. The symbolic references in the runtime constant pool are derived from structures in the binary representation of the class or interface as follows:
CONSTANT_Class_info
structure (§4.4.1) in the binary representation of a class or interface. Such a reference gives the name of the class or interface in the form returned by the Class.getName
method, that is:
Class.getName
method.
CONSTANT_Fieldref_info
structure (§4.4.2) in the binary representation of a class or interface. Such a reference gives the name and descriptor of the field, as well as a symbolic reference to the class or interface in which the field is to be found.
CONSTANT_Methodref_info
structure (§4.4.2) in the binary representation of a class or interface. Such a reference gives the name and descriptor of the method, as well as a symbolic reference to the class in which the method is to be found.
CONSTANT_InterfaceMethodref_info
structure (§4.4.2) in the binary representation of a class or interface. Such a reference gives the name and descriptor of the interface method, as well as a symbolic reference to the interface in which the method is to be found.
constant_pool
table:
CONSTANT_String_info
structure (§4.4.3) in the binary representation of a class or interface. The CONSTANT_String_info
structure gives the sequence of Unicode characters constituting the string literal.
String
. In addition, if the method String.intern
is called on any string, the result is a reference to the same class instance that would be returned if that string appeared as a literal. Thus,
must have the value(
"a
" + "b
" + "c
").intern()
== "abc
"
true
.
CONSTANT_String_info
structure.
String.intern
has previously been called on an instance of class String
containing a sequence of Unicode characters identical to that given by the CONSTANT_String_info
structure, then the result of string literal derivation is a reference to that same instance of class String
.
String
is created containing the sequence of Unicode characters given by the CONSTANT_String_info
structure; that class instance is the result of string literal derivation. Finally, the intern
method of the new String
instance is invoked.
CONSTANT_Integer_info
, CONSTANT_Float_info
, CONSTANT_Long_info
, or CONSTANT_Double_info
structures (§4.4.4, §4.4.5) in the binary representation of a class or interface. Note that CONSTANT_Float_info
structures represent values in IEEE 754 single format and CONSTANT_Double_info
structures represent values in IEEE 754 double format (§4.4.4, §4.4.5). The runtime constant values derived from these structures must thus be values that can be represented using IEEE 754 single and double formats, respectively.
constant_pool
table of the binary representation of a class or interface, the CONSTANT_NameAndType_info
(§4.4.6) and CONSTANT_Utf8_info
(§4.4.7) structures are only used indirectly when deriving symbolic references to classes, interfaces, methods, and fields, and when deriving string literals.public
class method void
main(String[])
. The invocation of this method drives all further
execution. Execution of the Java virtual machine instructions constituting the
main
method may cause linking (and consequently creation) of additional classes
and interfaces, as well as invocation of additional methods.
In some implementations of the Java virtual machine the initial class could be provided as a command line argument, as in JDK releases 1.0 and 1.1. Alternatively, the initial class could be provided by the implementation. In this case the initial class might set up a class loader that would in turn load an application, as in the Java 2 SDK, Standard Edition, v1.2. Other choices of the initial class are possible so long as they are consistent with the specification given in the previous paragraph.
If C is not an array class, it is created by loading a binary representation of C (see Chapter 4, "The class File Format") using a class loader (§2.17.2). Array classes do not have an external binary representation; they are created by the Java virtual machine rather than by a class loader.
There are two types of class loaders: user-defined class loaders and the bootstrap class loader supplied by the Java virtual machine. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader
. Applications employ class loaders in order to extend the manner in which the Java virtual machine dynamically loads and thereby creates classes. User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.
A class loader L may create C by defining it directly or by delegating to another class loader. If L creates C directly, we say that L defines C or, equivalently, that L is the defining loader of C.
When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.
At run time, a class or interface is determined not by its name alone, but by a pair: its fully qualified name and its defining class loader. Each such class or interface belongs to a single runtime package. The runtime package of a class or interface is determined by the package name and defining class loader of the class or interface.
The Java virtual machine uses one of three procedures to create class or interface C denoted by N:
First, the Java virtual machine determines whether the bootstrap class loader has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary.
Otherwise, the Java virtual machine performs one of the following two operations in order to load C:
Typically, a class or interface will be represented using a file in a hierarchical file system. The name of the class or interface will usually be encoded in the pathname of the file.
This phase of loading must detect the following error:
NoClassDefFoundError
or an instance of one of its subclasses.
Then the Java virtual machine attempts to derive a class denoted by N using the bootstrap class loader from the purported representation using the algorithm found in Section 5.3.5. That class is C.
loadClass
method on L. The result of the invocation is C. The Java virtual machine then records that the bootstrap loader is an initiating loader of C (§5.3.4).
First, the Java virtual machine determines whether L has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary.
Otherwise the Java virtual machine invokes loadClass(
N )
on L.1 The value returned by the invocation is the created class or interface C. The Java virtual machine then records that L is an initiating loader of C (§5.3.4). The remainder of this section describes this process in more detail.
When the loadClass
method of the class loader L is invoked with the name N of a class or interface C to be loaded, L must perform one of the following two operations in order to load C :
ClassFile
structure (§4.1); it then must invoke the method defineClass
of class ClassLoader
. Invoking defineClass
causes the Java virtual machine to derive a class or interface denoted by N using L from the array of bytes using the algorithm found in Section 5.3.5.loadClass
method). The result of the invocation is C.
If L has already been recorded as an initiating loader of an array class with the same component type as N, that class is C, and no array class creation is necessary. Otherwise, the following steps are performed to create C:
public
.
When a class or interface C = <N1, L1> makes a symbolic reference to a field or method of another class or interface D = <N2, L2> , the symbolic reference includes a descriptor specifying the type of the field, or the return and argument types of the method. It is essential that any type name N mentioned in the field or method descriptor denote the same class or interface when loaded by L1 and when loaded by L2.
To ensure this, the Java virtual machine imposes loading constraints of the form NL1 = NL2 during preparation (§5.4.2) and resolution (§5.4.3). To enforce these constraints, the Java virtual machine will, at certain prescribed times (see §5.3.1, §5.3.2, §5.3.3, and §5.3.5), record that a particular loader is an initiating loader of a particular class. After recording that a loader is an initiating loader of a class, the Java virtual machine must immediately check to see if any loading constraints are violated. If so, the record is retracted, the Java virtual machine throws a LinkageError
, and the loading operation that caused the recording to take place fails.
Similarly, after imposing a loading constraint (see §5.4.2, §5.4.3.2, §5.4.3.3, and §5.4.3.4), the Java virtual machine must immediately check to see if any loading constraints are violated. If so, the newly imposed loading constraint is retracted, the Java virtual machine throws a LinkageError
, and the operation that caused the constraint to be imposed (either resolution or preparation, as the case may be) fails.
The situations described here are the only times at which the Java virtual machine checks whether any loading constraints have been violated. A loading constraint is violated if, and only if, all the following four conditions hold:
class
File Representationclass
file format.
LinkageError
.This phase of loading must detect the following errors:
class
file format (§4.1, pass 1 of §4.9.1), loading throws an instance of ClassFormatError
.
UnsupportedClassVersionError
.2
NoClassDefFoundError
or an instance of one of its subclasses.
Object
as its direct superclass, which must already have been loaded. Only Object
has no direct superclass.
Any exceptions that can be thrown due to class or interface resolution can be thrown as a result of this phase of loading. In addition, this phase of loading must detect the following errors:
IncompatibleClassChangeError
.
ClassCircularityError
.
Any exceptions that can be thrown due to class or interface resolution can be thrown as a result of this phase of loading. In addition, this phase of loading must detect the following errors:
IncompatibleClassChangeError
.
ClassCircularityError
.
Verification must detect the following error:
VerifyError
.
During preparation of a class or interface C, the Java virtual machine also imposes loading constraints (§5.3.4). Let L1 be the defining loader of C. For each method m declared in C that overrides a method declared in a superclass or superinterface
Preparation may occur at any time following creation but must be completed prior to initialization.
Resolution can be attempted on a symbolic reference that has already been resolved. An attempt to resolve a symbolic reference that has already successfully been resolved always succeeds trivially and always results in the same entity produced by the initial resolution of that reference.
Subsequent attempts to resolve a symbolic reference that the Java virtual machine has previously unsuccessfully attempted to resolve always fails with the same error that was thrown as a result of the initial resolution attempt.
Certain Java virtual machine instructions require specific linking checks when resolving symbolic references. For instance, in order for a getfield instruction to successfully resolve the symbolic reference to the field on which it operates it must complete the field resolution steps given in Section 5.4.3.2. In addition, it must also check that the field is not
Linking exceptions generated by checks that are specific to the execution of a particular Java virtual machine instruction are given in the description of that instruction and are not covered in this general discussion of resolution. Note that such exceptions, although described as part of the execution of Java virtual machine instructions rather than resolution, are still properly considered failure of resolution.
The Java virtual machine instructions anewarray, checkcast, getfield, getstatic, instanceof, invokeinterface, invokespecial, invokestatic, invokevirtual, multianewarray, new, putfield, and putstatic make symbolic references to the runtime constant pool. Execution of any of these instructions requires resolution of its symbolic reference.
The following sections describe the process of resolving a symbolic reference in the runtime constant pool (§5.1) of a class or interface D. Details of resolution differ with the kind of symbolic reference to be resolved.
This condition can occur, for example, if C is a class that was originally declared to be
When resolving a field reference, field resolution first attempts to look up the referenced field in C and its superclasses:
Otherwise, let <E, L1> be the class or interface in which the referenced field is actually declared and let L2 be the defining loader of D. Let T be the name of the type of the referenced field. The Java virtual machine must impose the loading constraint that TL1=TL2(§5.3.4).
When resolving a method reference:
Otherwise, let <E, L1> be the class or interface in which the referenced method is actually declared and let L2 be the defining loader of D. Let T0 be the name of the type returned by the referenced method, and let T1, ..., Tn be the names of the argument types of the referenced method. The Java virtual machine must impose the loading constraints TiL1=TiL2 for i = 0 to n (§5.3.4).
When resolving an interface method reference:
A class or interface may be initialized only as a result of:
2
Contents | Prev | Next | Index
The JavaTM Virtual Machine Specification 5.4.3 Resolution
The process of dynamically determining concrete values from symbolic references
in the runtime constant pool is known as resolution.
static
. If it is a static
field, a linking exception must be thrown. 5.4.3.1 Class and Interface Resolution
To resolve an unresolved symbolic reference from D to a class or interface C
denoted by N, the following steps are performed:
If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, resolution
fails, and D is prohibited from accessing C.
IllegalAccessError
.
public
but was changed to be non-public
after D was compiled.
5.4.3.2 Field Resolution
To resolve an unresolved symbolic reference from D to a field in a class or interface
C, the symbolic reference to C given by the field reference must first be resolved
(§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution
of a class or interface reference can be thrown as a result of failure of field resolution.
If the reference to C can be successfully resolved, an exception relating to
the failure of resolution of the field reference itself can be thrown.
If field lookup fails, field resolution throws a NoSuchFieldError
. Otherwise, if field lookup succeeds but the referenced field is not accessible (§5.4.4) to D, field resolution throws an IllegalAccessError
.5.4.3.3 Method Resolution
To resolve an unresolved symbolic reference from D to a method in a class C, the
symbolic reference to C given by the method reference is first resolved (§5.4.3.1).
Therefore, any exceptions that can be thrown due to resolution of a class reference
can be thrown as a result of method resolution. If the reference to C can be successfully
resolved, exceptions relating to the resolution of the method reference itself
can be thrown.
If method lookup fails, method resolution throws a IncompatibleClassChangeError
.
NoSuchMethodError
. If method lookup succeeds and the method is abstract
, but C is not abstract
, method resolution throws an AbstractMethodError
. Otherwise, if the referenced method is not accessible (§5.4.4) to D, method resolution throws an IllegalAccessError
.5.4.3.4 Interface Method Resolution
To resolve an unresolved symbolic reference from D to an interface method in an
interface C, the symbolic reference to C given by the interface method reference is
first resolved (§5.4.3.1). Therefore, any exceptions that can be thrown as a result of
failure of resolution of an interface reference can be thrown as a result of failure of
interface method resolution. If the reference to C can be successfully resolved,
exceptions relating to the resolution of the interface method reference itself can be
thrown.
Otherwise, let <E, L1> be the interface in which the referenced interface method is actually declared and let L2 be the defining loader of D. Let T0 be the name of the type returned by the referenced method, and let T1, ..., Tn be the names of the argument types of the referenced method. The Java virtual machine must impose the loading constraints TiL1 = TiL2 for i = 0 to n (§5.3.4).IncompatibleClassChangeError
.Object
, interface method resolution throws a NoSuchMethodError
.
5.4.4 Access Control
A class or interface C is accessible to a class or interface D if and only if either of the
following conditions are true:
A field or method R is accessible to a class or interface D if and only if any of the
following conditions is true:
public
.
This discussion of access control omits a related restriction on the target of a public
.protected
and is declared in a class C, and D is either a subclass of C or C itself.protected
or package private (that is, neither public
nor protected
nor private
), and is declared by a class in the same runtime package as D.private
and is declared in D.
protected
field access or method invocation (the target must be of class D or a subtype of D). That requirement is checked as part of the verification process (§5.4.1); it is not part of link-time access control.5.5 Initialization
Initialization of a class or interface consists of invoking its static initializers
(§2.11) and the initializers for static fields (§2.9.2) declared in the class. This process
is described in more detail in §2.17.4 and §2.17.5.
Prior to initialization a class or interface must be linked, that is, verified, prepared,
and optionally resolved.
Class
or in package java.lang.reflect
. 5.6 Binding Native Method Implementations
Binding is the process by which a function written in a language other than the Java
programming language and implementing a native
method is integrated into the
Java virtual machine so that it can be executed. Although this process is traditionally
referred to as linking, the term binding is used in the specification to avoid confusion
with linking of classes or interfaces by the Java virtual machine.
1
Since JDK release 1.1 the Java virtual machine invokes the loadClass
method of a class loader in order to cause it to load a class or interface. The argument to loadClass
is the name of the class or interface to be loaded. There is also a two-argument version of the loadClass
method. The second argument is a boolean
that indicates whether the class or interface is to be linked or not. Only the two-argument version was supplied in JDK release 1.0.2, and the Java virtual machine relied on it to link the loaded class or interface. From JDK release 1.1 onward, the Java virtual machine links the class or interface directly, without relying on the class loader.UnsupportedClassVersionError
was introduced in the Java 2 platform, Standard Edition, v1.2. In earlier versions of the platform an instance of NoClassDefFoundError
or ClassFormatError
was thrown in case of an unsupported version depending on whether the class was being loaded by the system class loader or a user-defined class loader.
Copyright © 1999 Sun Microsystems, Inc.
All rights reserved
Please send any comments or corrections to [email protected]