Эккель Брюс
Шрифт:
// Вложенные (статические внутренние) классы
public class Parcel 11 {
private static class PContents implements Contents { private int i = 11; public int valueO { return i; }
}
protected static class ParcelDestination implements Destination { private String label;
private Parcel Destination(String whereTo) { label = whereTo,
}
public String readLabelO { return label; }
// Вложенные классы могут содержать другие статические элементы;
public static void f {}
static int x = 10;
static class AnotherLevel {
public static void f {} static int x = 10;
}
}
public static Destination destination(String s) { return new ParcelDestination(s);
}
public static Contents contO {
return new Parcel Contents О,
}
public static void main(String[] args) { Contents с = contentsO, Destination d = destinationC'TacMaHHfl"),
}
} ///;-
В методе main не требуется объекта класса Parcelll; вместо этого для вызова методов, возвращающих ссылки на Contents и Destination, используется обычный синтаксис обращения к статическим членам класса.
Как было сказано ранее, в обычном (не-статическом) внутреннем классе для обращения к объекту внешнего класса используется специальная ссылка this. Во вложенном классе такая ссылка недействительна (по аналогии со статическими методами).
Классы внутри интерфейсов
Обычно интерфейс не может содержать программный код, но вложенный класс может стать его частью. Любой класс, размещенный внутри интерфейса, автоматически является public и static. Так как класс является статическим, он не нарушает правил обращения с интерфейсом — этот вложенный класс просто использует пространство имен интерфейса. Во внутреннем классе даже можно реализовать окружающий интерфейс:
//• innerclasses/ClassInlnterface.java // {main: ClassInlnterfaceSTest}
public interface Classlnlnterface { void howdyO;
class Test implements Classlnlnterface { public void howdyO {
System. out.printlnCnpHBeT!");.
}
public static void main(String[] args) { new Test О .howdyO.
}
}
} /* Output Привет! *///•-
Вложение классов в интерфейсы может пригодиться для создания обобщенного кода, используемого с разными реализациями этого интерфейса.
Ранее в книге я предлагал помещать в каждый класс метод main, позволяющий при необходимости протестировать данный класс. Недостатком такого подхода является дополнительный скомпилированный код, увеличивающий размеры программы. Если для вас это нежелательно, используйте статический внутренний класс для хранения тестового кода:
//• innerclasses/TestBed.java
// Помещение тестового кода во вложенный класс
// {main: TestBedSTester}
public class TestBed {
public void f { System.out.printlnC'fO"): } public static class Tester {
public static void main(String[] args) { TestBed t = new TestBedO; t.fO:
}
}
} /* Output: f *///:-
При компиляции этого файла создается отдельный класс с именем TestBed$ Tester (для запуска тестового кода наберите команду java TestBed$Tester). Вы можете использовать этот класс для тестирования, но включать его в окончательную версию программы необязательно; файл TestBed$Tester.class можно просто удалить перед окончательной сборкой программы.
Доступ вовне из многократно вложенных классов
Независимо от глубины вложенности, внутренний класс всегда может напрямую обращаться ко всем членам всех классов, в которые он встроен. Следующая программа демонстрирует этот факт1:
//: innerclasses/MultiNestingAccess.java // Вложенные классы могут обращаться ко всем членам всех // классов, в которых они находятся.
class MNA {
private void f {} class A {
private void g {} public class В {
void h {
g;
f:
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args) { MNA mna = new MNA; MNA.A mnaa = mna.new AO; MNA.А.В mnaab = mnaa.new BO; mnaab h;
}
} ///.-
Как видно из примера, в классе MNA.A.B методы f и д вызываются без дополнительных описаний (несмотря на то, что они объявлены как private). Этот пример также демонстрирует синтаксис, который следует использовать при создании объектов внутренних классов произвольного уровня вложенности из другого класса. Синтаксис .new обеспечивает правильную область действия, и вам не приходится уточнять имя класса при вызове конструктора.