The increment method appears to increment the x field of the enclosing Host instance. In fact, Unknown
also declares a field x and that field is inherited by Helper. The inherited x field hides the x field from the
enclosing scope, and so it is the inherited x field that is incremented not the field that is seen in the source
code! To avoid giving the reader the wrong impression about what the code is doing, you should avoid the use
of simple names in this situation. Instead, the reference to x should be explicitly qualified as either this.x
or Host.this.x, depending on which field it is meant to refer to.
An inner class method with the same name as an enclosing class method hides all overloaded forms of the
enclosing class method, even if the inner class itself does not declare those overloaded forms. For example:
class Outer {
void print() { }
void print(int val) { }
class Inner {
void print() { }
void show() {
print();
Outer.this.print();
print(1); // INVALID: no Inner.print(int)
}
}
}
Here the declaration of Inner.print hides all forms of Outer.print. When Inner.show invokes
print(1), the compiler reports that Inner has no method print that takes an integer argument. The
show method must explicitly qualify the method invocation with Outer.this. There is a good reason to do
this. Normally, a set of overloaded methods within a class have the same basic contractthey just operate on
different parameter types. If an inner class method happens to have the same name as an enclosing class
method, there is no reason to assume that it supports the same contractconsequently, the hiding of the
enclosing class's overloaded forms prevents a completely unrelated method from being accidentally invoked.
As usual, there are few reasons to hide fields or methods in this way, so the issue is best avoided in the first
place. The details of how method invocations are resolved are discussed in "Finding the Right Method" on
page 224.
5.3. Local Inner Classes
You can define inner classes in code blocks, such as a method body, constructor, or initialization block. These
local inner classes are not members of the class of which the code is a part but are local to that block, just as a
local variable is. Such classes are completely inaccessible outside the block in which they are definedthere is
simply no way to refer to them. But instances of such classes are normal objects that can be passed as
arguments and returned from methods, and they exist until they are no longer referenced. Because local inner
classes are inaccessible, they can't have access modifiers, nor can they be declared static because, well,
they are local inner classes. All of the other class modifiers, including annotations, can be applied, though
only strictfp and annotations have practical applications.
A local inner class can access all the variables that are in scope where the class is definedlocal variables,
method parameters, instance variables (assuming it is a non-static block), and static variables. The only
restriction is that a local variable or method parameter can be accessed only if it is declared final. The
reason for this restriction relates mainly to multithreading issues (see Chapter 14) and ensures that all such
variables have well-defined values when accessed from the inner class. Given that the method accessing the