Inner Classes Specification
How do inner classes affect the organization of the Java Virtual Machine?
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.
There are no changes to the class file format as processed by the Java Virtual
Machine, or to the standard class libraries. The new features are implemented
by the compiler. The organization of the resulting bytecodes is specified with
enough precision that all 1.1-conforming compilers will produce binary
compatible class files.
A single file of Java source code can compile to many class files. Although this
is not a new phenomenon, the power of the inner class notation means that the
programmer can end up creating a larger number of class files with relatively
less code. In addition, adapter classes tend to be very simple, with few
methods. This means that a Java program which uses many inner classes will
compile to many small class files. Packaging technologies for such classes
process them reasonably efficiently. For example, the class file for the example
FixedStack.Enumeration occupies about three quarters of a kilobyte,
of which about 40% is directly required to implement its code. This ratio is
likely to improve over time as file formats are tuned. The memory usage
patterns in the virtual machine are comparable.
Class name transformations
Names of nested classes are transformed as necessary by the compiler to avoid
conflicts with identical names in other scopes. Names are encoded to the
virtual machine by taking their source form, qualified with dots, and changing
each dot `
.' after a class name into a dollar sign `
$'. (Mechanical translators are
allowed to use dollar signs in Java.)
When a class name is
private or local to a block, it is globally inaccessible. A
compiler may opt to code such an inaccessible name by using an accessible
enclosing class name as a prefix, followed by a `
$' separator and a locally
unique decimal number. Anonymous classes must be encoded this way.
So, an inner class
pkg.Foo.Bar gets a run-time name of
perhaps something like
pkg.Foo$23, if Bar is a
private member or local
class. Implementations must conform to the format of names, even globally
inaccessible ones, so that debuggers and similar tools can recognize them.
Any class file which defines or uses a transformed name also contains an
attribute (as supported by the 1.0 file format) recording the transformation.
These attributes are ignorable by the virtual machine and by 1.0 compilers.
The format of this attribute is described in the section on binary compatibility.
Names of generated variables and methods
As we have seen previously, if an inner class uses a variable from an enclosing
scope, the name expression will be transformed, into a reference either to a
field of an enclosing instance, or to a field of the current instance which
provides the value of a
final local variable. A reference to an enclosing
instance, in turn, is transformed into a reference to a field in a more accessible
current instance. These techniques require that the compiler synthesize hidden
fields in inner classes.
There is one more category of compiler-generated members. A
member m of a class C may be used by another class D, if one class encloses the
other, or if they are enclosed by a common class. Since the virtual machine
does not know about this sort of grouping, the compiler creates a local protocol
of access methods in C to allow D to read, write, or call the member m. These
methods have names of the form
access$1, etc. They are never
public. Access methods are unique in that they may be added to enclosing
classes, not just inner classes.
All generated variables and methods are declared in a class file attribute, so
that the 1.1 compilers can prevent programs from referring to them directly.
If an inner class C requires access to a
private member m of an enclosing
class T, the inserted access method for m opens up T to illegal access by any
class K in the same package. There at present are no known security problems
with such access methods, since it is difficult to misuse a method with package
scope. The compiler can be instructed to emit warnings when it creates access
methods, to monitor the creation of possible loopholes.
If a class N is a
protected member of another class C, then N's class file
defines it as a
public class. A class file attribute correctly records the
protection mode bits. This attribute is ignored by the current virtual machine,
which therefore will allow access to N by any class, and not just to subclasses
of C. The compiler, of course, will correctly diagnose such errors, because it
looks at the attribute. This is not a security hole, since malicious users can
easily create subclasses of C and so gain access to N,
protected or not.
Likewise, if a class is a
private member of another class, its class file defines
it as having package scope, and an attribute declares the true access protection,
so that 1.1 compilers can prevent inadvertant access, even within the package.