Sponsored Link •
|
Advertisement
|
A Java type can refer symbolically to another type in the constant pool in ways that require special
attention when performing resolution to ensure type safety in the presence of multiple class loaders. When
one type contains a symbolic reference to a field in another type, the symbolic reference includes a descriptor
that specifies the type of the field. When one type contains a symbolic reference to a method in another type,
the symbolic reference includes a descriptor that specifies the types of the return value and parameters, if
any. If the referenced and referencing types do not have the same initiating loader, the virtual machine must
make sure the types mentioned in the field and method descriptors are consistent across the namespaces. For
example, imagine class Cat
contains symbolic references to fields and methods declared
in class Mouse
, and that two different class loaders initiated the loading of
Cat
and Mouse
. To preserve type safety in the presence of multiple
class loaders, it is essential that the fully qualified type names mentioned in field and method descriptors
contained in Cat
refer to the same type data (in the method area) as those same names
in class Mouse
.
To ensure that Java virtual machine implementations enforce this type consistency across namespaces, the second edition of the Java virtual machine specification defined several loading constraints. Each Java virtual machine must maintain an internal list of these constraints, each of which basically states that a name in one namespace must refer to the same type data in the method area as the same name in another namespace. As a Java virtual machine encounters symbolic references to fields and methods of referenced types whose loading wasn't initiated by the same class loader that initiated loading of the referencing type, the virtual machine may add constraints to the list. The virtual machine must check that all current loading constraints are met when it resolves symbolic references.
To describe the loading constraints, the notation
will be
used to represent types. C
denotes the fully qualified name of the type.
Ld
denotes the defining class loader of the type. Li
denotes the
class loader that initiated loading of the type. When the defining class loader is irrelevant, the simplified
notation C
will be used to denote the type and its initiating class loader.
When the initiating loader is irrelevant, the simplified notation
will be used to
denote the type and its defining class loader. An equals sign between two types denotes that both types are
actually the exact same type, represented by the same type data in the method area.
Given this notation, the rules for generating loading constraints are:
to a field of type
T
declared in class
, the virtual machine must generate the
loading constraint:
TL1 = TL2
to a method with
return type T0
and parameter types (T1, ...,
Tn)
declared in class
, the virtual machine must
generate the loading constraint: T0L1 = T0L2
, ...,TnL1 = TnL2
overrides a method with return type
T0
and parameter types (T1, ...,
Tn)
declared in class
, the virtual machine must
generate the loading constraint: T0L1 = T0L2
, ...,TnL1 = TnL2
If the virtual machine's internal list of constraints contains the two constraints
TL1 = TL2
and TL2 =
TL3
, this implies that TL1 = TL3
.
Even if type T
is never loaded by L2
during the execution of the
virtual machine instance, the types named T
loaded by L1
and
L3
must still be the same exact type.
For a less mathematical look at loading constraints, refer to the last example in this chapter. This example, which is presented in the section titled "Example: Type Safety and Loading Constraints," shows how the lack of loading constraints can enable an industrious cracker to thwart the Java virtual machine's guarantee of type safety.
Sponsored Links
|