Все нестатические вложенные классы называются внутренними (inner). В них нельзя объявлять статические члены.
Локальные классы, как и все локальные переменные, известны только в блоке, в котором они определены. Они могут быть безымянными (anonymous classes).
В листинге 2.7 рассмотрены все эти случаи.
Листинг 2.7. Вложенные классы
class Nested{
static private int pr; // Переменная pr объявлена статической,
// чтобы к ней был доступ из статических классов A и AB.
String s = "Member of Nested";
// Вкладываем статический класс.
static class A{ // Полное имя этого класса — Nested.A
private int a = pr;
String s = "Member of A";
// Во вложенный класс A вкладываем еще один статический класс. static class AB{ // Полное имя класса — Nested.A.AB
private int ab = pr;
String s = "Member of AB";
}
}
// В класс Nested вкладываем нестатический класс. class B{ // Полное имя этого класса — Nested.B
private int b = pr;
String s = "Member of B";
// В класс B вкладываем еще один класс.
class BC{ // Полное имя класса — Nested.B.BC
private int bc = pr;
String s = "Member of BC";
}
void f(final int i){ // Без слова final переменные i и j
// нельзя использовать в локальном классе D.
final int j = 99;
class D{ // Локальный класс D известен только внутри f().
private int d = pr;
String s = "Meimoer of D"; void pr(){
// Обратите внимание на то, как различаются // переменные с одним и тем же именем "s". System.out.println(s + (i+j)); // "s" эквивалентно "this.s".
System.out.println(B.this.s);
System.out.println(Nested.this.s);
// System.out.println(AB.this.s); // Нет доступа.
// System.out.println(A.this.s); // Нет доступа.
}
}
D d = new D(); // Объект определяется тут же, в методе f().
d.pr(); // Объект известен только в методе f().
}
}
void m(){
new Object(){ // Создается объект безымянного класса,
// указывается конструктор его суперкласса.
private int e = pr; void g(){
System.out.println("From g()");
}
}.g(); // Тут же выполняется метод только что созданного объекта.
}
}
public class NestedClasses{
public static void main(String[] args){
Nested nest = new Nested(); // Последовательно раскрываются
// три матрешки.
Nested.A theA = nest.new A(); // Полное имя класса и уточненная
// операция new. Но конструктор только вложенного класса.
Nested.A.AB theAB = theA.new AB(); // Те же правила.
// Операция new уточняется только одним именем.
Nested.B theB = nest.new B(); // Еще одна матрешка.
Nested.B.BC theBC = theB.new BC();
theB.f(999); // Методы вызываются обычным образом.
nest.m();
}
}
Ну как? Поняли что-нибудь? Если вы все поняли и готовы применять эти конструкции в своих программах, значит, вы можете перейти к следующему разделу. Если ничего не поняли, значит, вы — нормальный человек. Помните принцип KISS и используйте вложенные классы как можно реже.
Теперь дадим пояснения.
□ Как видите, доступ к полям внешнего класса Nested возможен отовсюду, даже к закрытому полю pr. Именно для этого в Java и введены вложенные классы. Остальные конструкции добавлены вынужденно, для того чтобы увязать концы с концами.
□ Язык Java позволяет использовать одни и те же имена в разных областях видимости -поэтому пришлось уточнять константу this именем класса: Nested.this, B.this.
□ В безымянном классе не может быть конструктора, ведь имя конструктора должно совпадать с именем класса, — поэтому пришлось использовать имя суперкласса, в примере это класс Object. Вместо конструктора в безымянном классе используется блок инициализации экземпляра, о котором говорилось в предыдущем разделе.
□ Нельзя создать экземпляр вложенного класса, не создав предварительно экземпляр внешнего класса, — поэтому пришлось подстраховать это правило уточнением операции new именем экземпляра внешнего класса nest. new, theA. new, theB. new.
□ При определении экземпляра указывается полное имя вложенного класса, но в операции new записывается просто конструктор класса.
Введение вложенных классов сильно усложнило синтаксис и поставило много задач разработчикам языка. Это еще не все. Дотошный читатель уже зарядил новую обойму вопросов.
□ Можно ли наследовать вложенные классы? Можно.
□ Как из подкласса обратиться к методу суперкласса? Константа super уточняется именем соответствующего суперкласса, подобно константе this.
□ А могут ли вложенные классы быть расширениями других классов? Могут.
□ А как?.. Помните принцип KISS!!!
Механизм вложенных классов станет понятнее, если посмотреть, какие файлы с байткодами создал компилятор:
□ Nested$1$D.class — локальный класс D, вложенный в класс Nested;
□ Nested$1.class — безымянный класс;
□ Nested$A$AB.class — класс Nested.A.AB;
□ Nested$A.class — класс Nested.A;
□ Nested$B$BC.class — класс Nested.B.BC;
□ Nested$B.class — класс Nested.B;
□ Nested.class — внешний класс Nested;
□ NestedClasses.class — класс с методом main ().
Читать дальше
Конец ознакомительного отрывка
Купить книгу