Inner Classes Specification
What are the new binary compatibility requirements for Java 1.1 classes?
Note: This Inner Classes Specification is available for download as part of the JDK1.1 End Of Life (EOL) section of the Sun website. It has been included here because most of the specification is still relevant to the current Java classfile definition. However, the information has not been transferred into the latest Java Virtual Machine Specification or made available elsewhere in Sun's online Java resources.
In order to binary ensure compatibility between bytecodes output for Java 1.1
compilers from different vendors, and to ensure proper applicability of
debuggers and similar tools to those bytecodes, Java makes certain
requirements on the form of the bytecodes produced. This section describes
the requirements, new in Java 1.1, which pertain to the implementation of
various kinds of inner and nested top-level classes.
Bytecode names of classes and interfaces
Instances of the Java Virtual Machines, and Java bytecodes, refer to reference
types by means of bytecode names which differ in detail from the names used in
Java source code. The bytecode name of a package member T is defined as the
name of the package, with every `.' replaced by `/', followed (if the package
name is not null) by another `/', and then by the simple name of T. The
bytecode name of T also serves as a prefix for the bytecode name of every class
defined within the body of T.
The bytecode name of a class C which is a non-private member of another
class, and which is not contained (directly or indirectly) in any block or
private class, is defined as the bytecode name of the immediately-enclosing
class, followed by `$', followed by the simple name of C.
All other classes are called inaccessible. No inaccessible class N can ever be
referenced by the code of any other compilation unit. Thus, as long as the
name of N is chosen by the compiler in such as way as not to conflict with any
other class in the same compilation unit, the name will be globally unique,
because (as required previously) its prefix is unique to the package member in
which it occurs.
For the sake of tools, there are some additional requirements on the naming of
an inaccessible class N. Its bytecode name must consist of the bytecode name
of an enclosing class (the immediately enclosing class, if it is a member),
followed either by `$' and a positive decimal numeral chosen by the compiler,
or by `$' and the simple name of N, or else by both (in that order). Moreover,
the bytecode name of a block-local N must consist of its enclosing package
member T, the characters `$1$', and N, if the resulting name would be unique.
The string produced by the getName method of Class is derived, in all of
these cases, from the bytecode name, by replacing `/' by `.'. There is no
attempt to "clean up" the name to make it resemble Java source code.
The class attribute InnerClasses
The bytecode output of a Java 1.1 compiler may refer (via CONSTANT_Class
entries) to bytecode names of classes or interfaces which are not package
members. If so, the bytecodes must also contain an class attribute called
InnerClasses which declares the encoding of those names. This attribute
contains an array of records, one for each encoded name:
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{
u2 inner_class_info_index; // CONSTANT_Class_info index
u2 outer_class_info_index; // CONSTANT_Class_info index
u2 inner_name_index; // CONSTANT_Utf8_info index
u2 inner_class_access_flags; // access_flags bitmask
} classes[number_of_classes]
}
|
Each array element records a class with an encoded name, its defining scope,
its simple name, and a bitmask of the originally declared, untransformed
access flags. If an inner class is not a member, its outer_class_info_index
is zero. If a class is anonymous, its inner_name_index is zero.
If a class C was declared protected, the public access flag bit is cleared in
its InnerClasses record, even though it is set in C's access_flags field.
If the outer_class_info_index of a record refers to a class E which itself is
not a package member, then an earlier record of the same InnerClasses
attribute must describe E.
If a class has members which are types, it must have an InnerClasses
attribute, with a record for each of the types. The rules already given imply
that a class which is not a package member has an InnerClasses attribute
which has a record for it and all of its enclosing classes, except the outermost.
These rules ensure that compilers and debuggers can correctly interpret
bytecode names without parsing them, and without opening additional files to
examine inner class definitions. Compilers are allowed to omit
InnerClasses records for inaccessible classes, but they are encouraged to
include records for all classes, especially when the code is being compiled for
use with a debugger.
The member attribute Synthetic
As discussed previously, the compiler synthesizes certain hidden fields and
methods in order to implement the scoping of names. These fields are
private unless noted otherwise, or they are at most of package scope.
Java 1.1 compilers are required, when producing bytecodes, to mark any field
or member not directly defined in the source code with an attribute named
Synthetic. (At present, the length must be zero.) This will allow other
compilers to avoid inadvertant source-level references to non-private hidden
members, and will allow tools to avoid displaying them unnecessarily.
(A corresponding mechanism for declaring a local variable to be Synthetic
may also be introduced.)
Java 1.1 compilers are strongly encouraged, though not required, to use the
following naming conventions when implementing inner classes. Compilers
may not use synthetic names of the forms defined here for any other purposes.
A synthetic field pointing to the outermost enclosing instance is named
this$0. The next-outermost enclosing instance is this$1, and so forth. (At
most one such field is necessary in any given inner class.) A synthetic field
containing a copy of a constant v is named val$v. These fields are final.
All these synthetic fields are initialized by constructor parameters, which have
the same names as the fields they initialize. If one of the parameters is the
innermost enclosing instance, it is the first. All such constructor parameters
are deemed to be synthetic. If the compiler determines that the synthetic
field's value is used only in the code of the constructor, it may omit the field
itself, and use only the parameter to implement variable references.
A non-private final synthetic method which grants access to a private
member or constructor has a name of the form access$N, where N is a
decimal numeral. The organization of such access protocols is unspecified.
Debuggers and similar tools which are 1.1 compatible must recognize these
naming conventions, and organize variable displays and symbol tables
accordingly. Note that tools may need to parse these names. Compilers are
strongly encouraged to use these conventions, at least by default.
Implementations of the Java Virtual Machine may verify and require that the
synthetic members specified here are defined and used properly. It is
reasonable to exploit the nature of synthetic members by basing optimization
techniques on them.
|