Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

ссылкаНаОбъемлющийКласс.super;

в теле конструктора. Оно обеспечит недостающую ссылку, и программа отком-пилируется.

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

Что происходит, если вы создаете внутренний класс, затем наследуете от его внешнего класса, а после этого заново описываете внутренний класс в производном

Можно ли переопределить внутренний класс? 273

классе? Другими словами, можно ли переопределить внутренний класс? Это было бы довольно интересно, но «переопределение» внутреннего класса, как если бы он был еще одним методом внешнего класса, фактически не имеет никакого

эффекта:

//. innerclasses/BigEgg.java // Внутренний класс нельзя переопределить // подобно обычному методу, import static net.mindview util.Print.*:

class Egg {

private Yolk y; protected class Yolk {

public YolkO { printCEgg.YolkO"). }

}

public EggO {

printC'New EggO"): у = new YolkO:

public class BigEgg extends Egg { public class Yolk {

public YolkO { print("BigEgg YolkO"): }

}

public static void main(String[] args) { new BigEggO;

}

} /* Output New EggO Egg. YolkO *///•-

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

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

//: 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:

Поделиться:
Популярные книги

Воин

Бубела Олег Николаевич
2. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.25
рейтинг книги
Воин

Кодекс Охотника. Книга ХХХ

Винокуров Юрий
30. Кодекс Охотника
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Охотника. Книга ХХХ

Я уже царь. Книга XXIX

Дрейк Сириус
29. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я уже царь. Книга XXIX

Ермак. Регент

Валериев Игорь
10. Ермак
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ермак. Регент

Вечный. Книга III

Рокотов Алексей
3. Вечный
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга III

Ваше Сиятельство 2

Моури Эрли
2. Ваше Сиятельство
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Ваше Сиятельство 2

Одержимый

Джеймс Питер
Top Thriller
Детективы:
триллеры
маньяки
8.67
рейтинг книги
Одержимый

Локки 4 Потомок бога

Решетов Евгений Валерьевич
4. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Локки 4 Потомок бога

Кадет Морозов

Шелег Дмитрий Витальевич
4. Живой лёд
Фантастика:
боевая фантастика
5.72
рейтинг книги
Кадет Морозов

За Горизонтом

Вайс Александр
8. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
космоопера
5.00
рейтинг книги
За Горизонтом

Горизонт Вечности

Вайс Александр
11. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
космоопера
5.00
рейтинг книги
Горизонт Вечности

Геном хищника. Книга четвертая

Гарцевич Евгений Александрович
4. Я - Легенда!
Фантастика:
боевая фантастика
рпг
попаданцы
5.00
рейтинг книги
Геном хищника. Книга четвертая

Дитя прибоя

Трофимов Ерофей
Дитя прибоя
Фантастика:
боевая фантастика
попаданцы
фэнтези
5.00
рейтинг книги
Дитя прибоя

Я – Стрела. Трилогия

Суббота Светлана
Я - Стрела
Любовные романы:
любовно-фантастические романы
эро литература
6.82
рейтинг книги
Я – Стрела. Трилогия