objects associated with it, or it could have many.
When deposit creates an Action object, a reference to the enclosing BankAccount object is
automatically stored in the new Action object. Using this saved reference, the Action object can always
refer to the enclosing BankAccount object's number field by the simple name number, as shown in
toString. The name of the reference to the enclosing object is this preceded by the enclosing class
namea form known as qualified-this. For example, toString could reference the number field of the
enclosing BankAccount object explicitly:
return BankAccount.this.number + ": " + act + " " + amount;
The qualified-this reference reinforces the idea that the enclosing object and the inner object are tightly
bound as part of the same implementation of the enclosing class. This is further reinforced by the
qualified-super reference, which allows access to members of the enclosing instance's superclass that have
been hidden, or overridden, by the enclosing class. For example, given a class T that extends S, within T we
can invoke the superclass implementation of a method m, by using super.m() in an expression. Similarly,
in an inner class of T, we can invoke the same implementation of m using T.super.m() in an expressiona
qualified-super referenceand similarly for fields of S hidden by fields in T.
A nested class can have its own nested classes and interfaces. References to enclosing objects can be obtained
for any level of nesting in the same way: the name of the class and this. If class X encloses class Y which
encloses class Z, code in Z can explicitly access fields of X by using X.this.
The language does not prevent you from deeply nesting classes, but good taste should. A doubly nested class
such as Z has three name scopes: itself, its immediate enclosing class Y, and outermost class X. Someone
reading the code for Z must understand each class thoroughly to know in which context an identifier is bound
and which enclosing object was bound to which nested object. We recommend nesting only one level under
most circumstances. Nesting more than two levels invites a readability disaster and should probably never be
attempted.
5.2.2. Extending Inner Classes
An inner class can be extended just as any static nested class or top-level class can. The only requirement is
that objects of the extended class must still be associated with objects of the original enclosing class or a
subclass. Usually this is not a problem because the extended inner class is often declared within an extension
of the outer class:
class Outer {
class Inner { }
}
class ExtendedOuter extends Outer {
class ExtendedInner extends Inner { }
Inner ref = new ExtendedInner();
}
The ref field is initialized when an ExtendedOuter object is created. The creation of the
ExtendedInner instance uses the default no-arg constructor of ExtendedInner, which in turn
implicitly invokes the default no-arg constructor of Inner by using super. The constructor for Inner
requires an object of Outer to bind to, which in this case is implicitly the current object of
ExtendedOuter.