Философия Java

         

Может ли быть внутренний класс перегружен?


Что произойдет, когда Вы создадите внутренний класс, а затем наследуете окружающий класс и переопределите внутренний класс? Что же это такое, что возможно переопределить внутренний класс? Да, это именно так и выглядит, но переопределение внутреннего класса это то же самое, как если бы во внешнем классе был бы другой метод, который ничего бы не делал:

//: c08:BigEgg.java

// Внутренний класс не может быть переопределен

// как метод.

class Egg { protected class Yolk { public Yolk() { System.out.println("Egg.Yolk()"); } } private Yolk y; public Egg() { System.out.println("New Egg()"); y = new Yolk(); } }

public class BigEgg extends Egg { public class Yolk { public Yolk() { System.out.println("BigEgg.Yolk()"); } } public static void main(String[] args) { new BigEgg(); } } ///:~

Конструктор по умолчанию генерируется компилятором и эти вызовы конструктора базового класса тоже. Вы можете думать, что поскольку BigEgg уже создан, то будет использована переопределенная версия Yolk, но в действительности все не так. Вывод будет такой:

New Egg() Egg.Yolk()

Этот пример показывает, что нет никакой дополнительной магии в наследовании от внешнего класса. Два внутренних классов полностью разделены, каждый существует в своем собственном пространстве имен. Но все равно, остается возможность недвусмысленно наследовать от внутреннего класса:

//: c08:BigEgg2.java

// Правильное наследование от внутреннего класса.

class Egg2 { protected class Yolk { public Yolk() { System.out.println("Egg2.Yolk()"); } public void f() { System.out.println("Egg2.Yolk.f()"); } } private Yolk y = new Yolk(); public Egg2() { System.out.println("New Egg2()"); } public void insertYolk(Yolk yy) { y = yy; } public void g() { y.f(); } }

public class BigEgg2 extends Egg2 { public class Yolk extends Egg2.Yolk { public Yolk() { System.out.println("BigEgg2.Yolk()"); } public void f() { System.out.println("BigEgg2.Yolk.f()"); } } public BigEgg2() { insertYolk(new Yolk()); } public static void main(String[] args) { Egg2 e2 = new BigEgg2(); e2.g(); } } ///:~

Теперь BigEgg2.Yolk ясно расширяет Egg2.Yolk и переопределяет его методы. Метод insertYolk( ) позволяет BigEgg2 привести к базовому типу один из его объектов Yolk к ссылке y в Egg2, так что, когда g( ) вызывает y.f( ), то используется переопределенная версия f( ). Вывод же будет такой:

Egg2.Yolk() New Egg2() Egg2.Yolk() BigEgg2.Yolk() BigEgg2.Yolk.f()

Второй вызов Egg2.Yolk( ) это вызов конструктора базового класса из конструктора BigEgg2.Yolk. Вы так же можете видеть, что переопределенная версия f( ) используется, когда вызывается g( ).



Содержание раздела