Выбрать главу

public Wrapping wrapping(int x) {

// Вызов конструктора базового класса, return new Wrapping(x) { // аргумент конструктора public int valueO {

return super.valueO * 47;

}

}; // Требуется точка с запятой

}

public static void main(String[] args) { Parcel8 p = new Parcel80; Wrapping w = p.wrapping(lO);

}

} ///:-

Требуемый аргумент просто передается в конструктор базового класса, как в рассмотренном примере х в выражении new Wrapping(x). Хотя это обычный класс с реализацией, Wrapping также используется в качестве общего «интер­фейса» для своих производных классов:

II: innerclasses/Wrapping.java public class Wrapping { private int i,

public Wrapping(int x) { i = x; } public int valueO { return i; } } ///:-

Класс Wrapping имеет конструктор с аргументом — просто для того, чтобы ситуация стала чуть более интересной.

Точка с запятой в конце безымянного внутреннего класса поставлена вовсе не для того, чтобы обозначить конец тела класса (как делается в С++). Вместо этого она указывает на конец выражения, в котором содержится внутренний класс. Таким образом, в данном случае ее использование ничем не отличается от обычного.

Инициализацию также можно провести в точке определения полей безы­мянного класса:

II: innerclasses/Parcel9.java

II Безымянный внутренний класс, выполняющий инициализацию. II Более короткая версия программы Parcel5 java

public class Parcel9 {

II Для использования в безымянном внутреннем классе II аргументы должны быть неизменны (final); public Destination destination(final String dest) { return new Destination0 {

private String label = dest;

public String readLabelO { return label; }

}:

}

public static void main(String[] args) { Parcel9 p = new Parcel90; Destination d = p.destinationCTacMaHHfl").

}

Если вы определяете безымянный внутренний класс и хотите при этом ис­пользовать объекты, определенные вне этого внутреннего класса, компилятор требует, чтобы переданные на них ссылкй объявлялись неизменными (final), как это сделано аргументе destination(). Без такого объявления вы получите со­общение об ошибке при компиляции программы.

Пока мы ограничиваемся простым присваиванием значений полям, указан­ный подход работает. А если понадобится выполнить некоторые действия, свойственные конструкторам? В безымянном классе именованный конструктор определить нельзя (раз у самого класса нет имени!), но инициализация экземп­ляра (instance initialization) фактически позволяет добиться желаемого эф­фекта:

//. innerclasses/AnonymousConstructor.java

II Создание конструктора для безымянного внутреннего класса.

import static net.mindview.util.Print.*,

abstract class Base {

public Base(int i) {

print("Конструктор Base, i = " + i);

}

public abstract public void f();

}

public class AnonymousConstructor {

public static Base getBase(int i) { return new Base(i) {

{ рпгйС'Инициализация экземпляра"); } public void f() {

print ("Безымянный fO").

}

}.

}

public static void main(String[] args) { Base base = getBase(47); base.fO;

}).

}

} /* Output.

Конструктор Base, i = 47

Инициализация экземпляра

Безымянный f()

*///.-

В таком случае переменная i не обязана быть неизменной (final). И хотя i пе­редается базовому конструктору безымянного класса, она никогда не использу­ется напрямую внутри безымянного класса.

Вернемся к нашим объектам Parcel, на этот раз выполнив для них инициа­лизацию экземпляра. Отметьте, что параметры метода destination() должны быть объявлены неизменными, так как они используются внутри безымянно­го класса:

II- innerclasses/ParcellO.java

II Демонстрация "инициализации экземпляра" для

II конструирования безымянного внутреннего класса.                                     продолжение &

public class Parcel 10 { public Destination

destination(final String dest, final float price) { return new Destination() { private int cost,

// Инициализация экземпляра для каждого объекта. {

cost = Math round(price), if(cost > 100)

System out println("Превышение бюджета!"),

}

private String label = dest,

public String readLabelO { return label, }

}.

}

public static void main(String[] args) {

Parcel 10 p = new Parcel 100.

Destination d = p destination"Тасмания". 101 395F),

}

} /* Output- Превышение бюджета! */// -

Внутри инициализатора экземпляра виден код, недоступный при инициали­зации полей (то есть команда if). Поэтому инициализатор экземпляра фактиче­ски является конструктором безымянного внутреннего класса. Конечно, воз­можности его ограничены; перегружать такой инициализатор нельзя, и поэтому он будет присутствовать в классе только в единственном числе.

Возможности безымянных внутренних классов несколько ограничены по сравнению с обычным наследованием — они могут либо расширять класс, либо реализовывать интерфейс, но не то и другое одновременно. А если вы вы­берете второй вариант, реализовать можно только один интерфейс.

Снова о методе-фабрике

Посмотрите, насколько приятнее выглядит пример interfaces/Factories.java при использовании безымянных внутренних классов:

// innerclasses/Factories java import static net.mindview util Print *;

interface Service { void methodic), void method2(),

}

interface SemceFactory { Service getServiceO;

}

class Implementationl implements Service { private ImplementationlO {}

public void methodic) {printC"Implementationl methodl");} public void method2() {print("Implementationl method2");}

public static ServiceFactory factory = new ServiceFactoryO {

public Service getServiceO {

return new ImplementationlO;

class Implementation2 implements Service { private Implementation20 {}

public void methodlO {print("Implementation2 methodl"),) public void method2() {print("Implementation2 method2"),j public static ServiceFactory factory = new ServiceFactoryO {

public Service getServiceO {

return new Implementation2();

public class Factories {

public static void serviceConsumer(ServiceFactory fact) { Service s = fact.getServiceO; s methodlO; s method2();

}

public static void main(String[] args) {

serviceConsumer(Implementationl.factory); // Реализации полностью взаимозаменяемы: servi ceConsumer(Implementati on2.factory);

}

} /* Output- Implementationl methodl Implementationl method2 Implementation2 methodl Implementation2 method2 */// ~

Теперь конструкторы Implementationl и Implementation2 могут быть закрытыми, и фабрику необязательно оформлять в виде именованного класса. Кроме того, часто бывает достаточно одного фабричного объекта, поэтому в данном случае он создается как статическое поле в реализации Service. Наконец, итоговый син­таксис выглядит более осмысленно.

Пример interfaces/Games.java тоже можно усовершенствовать с помощью бе­зымянных внутренних классов:

//. innerclasses/Games.java

// Использование анонимных внутренних классов в библиотеке Game import static net.mindview.util.Print.*;

interface Game { boolean moveO; } interface GameFactory { Game getGameO; }

class Checkers implements Game { private Checkers О {} private int moves = 0;