27

27


}

public static void main(String[] args) { Parcel5 p = new Parcel50; Destination d = p destinationC'TacMaHHH");

}

} ///.-

Теперь класс PDestination является частью метода destination(), а не частью класса Parcel5. Поэтому доступ к классу PDestination возможен только из метода destination(). Обратите внимание на восходящее преобразование, производимое в команде return, — из метода возвращается лишь ссылка на базовый класс Destination, и ничего больше. Конечно, тот факт, что имя класса PDestination на­ходится внутри метода destination(), не означает, что объект PDestination после выхода из этого метода станет недоступным.

Идентификатор PDestination может использоваться для внутренних классов каждого отдельного класса в одном подкаталоге, без порождения конфликта имен.

Следующий пример демонстрирует, как можно вложить внутренний класс в произвольную область действия:

//. innerclasses/Parcel6 java

// Вложение класса в область действия

public class Parcel6 {

private void internalTracking(boolean b) { if(b) {

class TrackingSlip {

private String id;

TrackingSlipCString s) { id = s;

}

String getSlipO { return id; }

}

TrackingSlip ts = new TrackingSlipC'ожидание");

String s = ts getSlipO;

}

// Здесь использовать класс нельзя!

// Вне области видимости.

//! TrackingSlip ts = new Tracki ngSlipCx").

}

public void trackO { internalTracking(true), }

public static void main(String[] args) { Parcel6 p = new Parcel60; p trackO;

}

} ///:-

Класс TrackingSlip вложен в область действия команды if. Это не значит, чтокласссоздается в зависимости от условия — он компилируется вместе со всем остальным кодом. Однако при этом он недоступен вне контекста, в котором был определен. В остальном он выглядит точно так же, как и обычный класс.

Безымянные внутренние классы

Следующий пример выглядит немного странно:

// innerclasses/Parcel7 java

// Метод возвращает экземпляр безымянного внутреннего класса

public class Parcel7 {

public Contents contents О {

return new Contents О { // Вставить определение класса private int i = 11; public int valueO { return i; } }. // В данной ситуации точка с запятой необходима

}

public static void main(String[] args) { Parcel7 p = new Parcel7(); Contents с = p.contents О;

}

} ///-

Метод contents() совмещает создание возвращаемого значения с определени­ем класса, который это возвращаемое значение и представляет! Вдобавок, этот класс являетсябезымянным— у него отсутствует имя. Ситуация запутывается еще тем, что поначалу мы будто бы приступаем к созданию объекта Contents, а потом, остановившись перед точкой с запятой, говорим: «Стоп, а сюда я под­кину определение класса».

Такая необычная форма записи значит буквально следующее: «Создать объ­ект безымянного класса, который унаследован от Contents». Ссылка, которая возвращается при этом из выражения new, автоматически повышается до базо­вого типа Contents. Синтаксис записи безымянного внутреннего класса являет­ся укороченной формой записи такой конструкции:

//: innerclasses/Parcel7b.java

II Расширенная версия Parcel7.java

public class Parcel7b {

class MyContents implements Contents { private int i = 11; public int valueO { return i; }

}

public Contents contents О { return new MyContentsО; } public static void main(String[] args) { Parcel 7b p = new Parcel7b(); Contents с = p contentsO;

}

} ///-

В безымянном внутреннем классе базовый класс Contents создается с ис­пользованием конструктора по умолчанию. Следующая программа показывает, как следует поступать, если базовый класс требует вызова конструктора с аргу­ментами:

// innerclasses/Parcel8 java

// Вызов конструктора базового класса.

public class Parcel8 {продолжение &

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) фактически позволяет добиться желаемого эф­фекта:

Report Page