Этот пример просто показывает, что при наследовании от внешнего класса ничего особенного с внутренними классами не происходит. Два внутренних класса — совершенно отдельные составляющие, с независимыми пространствами имен. Впрочем, возможность явного наследования от внутреннего класса сохранилась:
//: innerclasses/BigEgg2.java
// Правильное наследование внутреннего класса,
i mport stati с net.mi ndvi ew.uti1.Pri nt.*;
class Egg2 {
protected class Yolk {
public YolkO { print("Egg2.YolkO"): } public void f() {
print("Egg2 Yolk.fO"):}
}
private Yolk у = new YolkO, продолжение &
public Egg2() { print("New Egg2()"); } public void insertYolk(Yolk yy) { у = yy; } public void g() { y.f(); }
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2 Yolk {
public YolkO{ print("BigEgg2.Yolk()"); }
public void f() { System.out.println("BigEgg2.Yolk.f()"); }
}
public BigEgg2() { insertYolk(new YolkO); } public static void main(String[] args) { Egg2 e2 = new BigEgg2(); e2.g();
}
} /* Output: Egg2. YolkO New Egg2() Egg2. YolkO BigEgg2. YolkO BigEgg2.Yolk.f() *///•-
Теперь класс BigEgg2.Yolk явно расширяет класс Egg2.Yolk и переопределяет его методы. Метод insertYolk() позволяет классу BigEgg2 повысить один из своих объектов Yolk до ссылки у в классе Egg2, поэтому при вызове y.f() в методе д() используется переопределенная версия f(). Второй вызов Egg2.Yolk() — это вызов конструктора базового класса из конструктора класса BigEgg2.Yolk. Мы также видим, что при вызове метода д() используется «обновленная» версия мето-даЮ.
Локальные внутренние классы
Как было замечено ранее, внутренние классы также могут создаваться в блоках кода — чаще всего в теле метода. Локальный внутренний класс не может иметь спецификатора доступа, так как он не является частью внешнего класса, но для него доступны все неизменные (final) переменные текущего блока и все члены внешнего класса. Следующий пример сравнивает процессысоздания локального внутреннего класса и безымянного внутреннего класса:
//: innerclasses/LocalInnerClass.java // Хранит последовательность объектов, import static net.mindview.util.Print.*;
interface Counter { int nextO;
}
public class LocalInnerClass { private int count = 0; Counter getCounter(final String name) { // Локальный внутренний класс: class Local Counter implements Counter { public Local CounterО {
return new Local CounterО;
}
// To же самое с безымянным внутренним классом: Counter getCounter2(final String name) { return new CounterO {
// У безымянного внутреннего класса не может быть // именованного конструктора, «легальна» только
// инициализация экземпляром: {
print ("Counter О");
}
public int next О {
printnb(name): // неизменный аргумент return count++:

}
public static void main(String[] args) {
LocalInnerClass lie = new LocalInnerClassO: Counter
cl = lic.getCounter(" локальный"), c2 = lic.getCounter2(" безымянный"): for(int i = 0: i < 5: i++) print(cl.nextO): for(int i = 0: i < 5: i++) print(c2.next());
}
}
} /* Output: Local CounterO CounterO локальный 0 локальный 1 локальный 2 локальный 3 локальный 4 безымянный 5 безымянный 6 безымянный 7 безымянный 8 безымянный 9 *///:-
Объект Counter возвращает следующее по порядку значение. Он реализован и как локальный класс, и как безымянный внутренний класс, с одинаковым поведением и характеристиками. Поскольку имя локального внутреннего класса недоступно за пределами метода, доводом для применения локального класса вместо безымянного внутреннего может быть необходимость в именованном конструкторе и (или) перегруженных конструкторах; безымянные внутренние классы допускают только инициализацию экземпляром.
// У локального внутреннего класса // может быть собственный конструктор: pri nt("Local Counter()");
}
public int next О {
printnb(name): // неизменный аргумент return count++;

Другая причина для использования локального внутреннего класса вместо безымянного внутреннего — необходимость создания более чем одного объекта такого класса.
Идентификаторы внутренних классов
Так как каждый класс компилируется в файл с расширением .class, содержащий полную информацию о создании его экземпляров (эта информация помещается в «мета-класс», называемый объектом Class), напрашивается предположение, что внутренние классы также создают файлы .class для хранения информации о своих объектах Class. Имена этих файлов-классов строятся по жестко заданной схеме: имя объемлющего внешнего класса, затем символ $ и имя внутреннего класса. Например, для программы LocallnnerClass.javaсоздаются следующие файлы с расширением .class:
Counter.class
LocalInnerClass$2.class
LocalInnerClass$lLocalCounter.class
LocalInnerClass.class
Если внутренние классы являются безымянными, компилятор использует в качестве их идентификаторов номера. Если внутренние классы вложены в другие внутренние классы, их имена просто присоединяются после символа $ и идентификаторов всех внешних классов.
Читать дальше