Вложенным классом называют класс, который является членом другого класса (находится в его теле). Существует четыре базовых типа вложенных классов в Java:
Вложенными классами описывают типы, которые будут использоваться только в одном классе или вообще будут использованы только один раз (анонимные классы). С помощью этих классов реализовывается необходимость разделить данные и методы их обработки в разные типы (сущности). Сохранив, при этом, инкапсуляцию.
В данном уроке будут рассмотрены только Static Nested classes (статические вложенные классы).
Static Nested classes используются для описания типа, который не должен зависеть от конкретного экземпляра внешнего класса, в который он вложен. Например, билдер — собирает очередной экземпляр внешнего класса и никак с ним больше не взаимодействует.
Static Nested class объявляется как и любой класс, НО внутри тела класса с ключевым словом static. Имена вложенных классов не имеют особых правил.
Static Nested class не имеет привязки к объекту внешнего класса (не хранит в себе ссылку на конкретный экземпляр внешнего класса).
Вложенный класс (Static Nested) имеет доступ к статическим членам своего внешнего класса, в том числе и к закрытым (private), даже без упоминания имени класса.
К НЕстатическим членам внешнего класса Nested(static) класс не имеет прямого доступа. Но такой доступ возможен через объект (экземпляр) внешнего класса, в том числе к закрытым (private) членам внешнего класса.
Вот код-пример:
/** Перед запуском этого кода — изучите логику кода.
* И не стесняйтесь экспериментировать с кодом!
*/
public class External {
private static int instanceCounter;
private int a;
int b;
public External(int a, int b) {
this.a = a;
this.b = b;
instanceCounter++;
}
// private // Смело экспериментируйте!
static void messenger(String incomeMessage) {
String someMessage = "No message!";
if (incomeMessage != null && !incomeMessage.isEmpty()) {
someMessage = incomeMessage;
}
System.out.printf("The static method 'messenger()' of the outer class. Message: "
+ "\"%s\"\n\n",
someMessage);
}
// Все, что нам нужно от объектов External.
String sum() {
int result = a + b;
return String.format("The non-static method 'sum()' of the outer class. %d + %d = %d",
a,
b,
result);
}
static class NestedFoo {
static String getInstanceCounter() {
// Свободный доступ к статическому полю внешнего класса:
return instanceCounter
+ " (the information is provided by a static method 'getInstanceCounter()' "
+ "from an inner class.)";
}
void methodFoExperiments() {
System.out.println("'methodFoExperiments()' method in inner class.");
// a = 5; // Ошибка! Ответьте себе почему?!
// b = 5; // Ошибка! Т.к. "а" не статическое поле.
// Свободный доступ к статическому методу внешнего класса,
// даже без упоминания имени внешнего класса или его объектов:
messenger("ПРЯМОЙ вызов 'messenger()' из 'methodFoExperiments()'");
// Или с упоминанием его имени:
External.messenger("ЧЕРЕЗ ИМЯ КЛАССА вызов 'messenger()' из "
+ "'methodFoExperiments()'");
// Создадим объект внешнего класса с псевдослучайными значениями полей:
External instanceInInner = new External(10, 10);
// теперь пощупаем эти поля через имя объекта:
instanceInInner.a = 5; // Доступ к private полю через объект.
instanceInInner.b = 5; // Доступ к default (package visible) полю через объект.
System.out.println(instanceInInner.sum());
messenger("After second instantiation in inner class. Counter = "
+ External.NestedFoo.getInstanceCounter());
}
}
}
// Где-то в этом же пакете класс:
class SomeMainClass {
public static void main(String[] args) {
// Потрогаем статический метод внешнего класса и статический метод статического внутреннего
// класса:
External.messenger("Before instantiation. instanceCounter = "
+ External.NestedFoo.getInstanceCounter());
// Создадим экземпляр внешнего класса с псевдослучайными значениями полей:
External instance = new External(2, 2);
// Вызовем у объекта НЕстатический метод с уровнем доступа default:
System.out.println("After first instance creation: " + instance.sum());
// Снова выведем на экран число инстансов внешнего класса:
External.messenger("After first instantiation. instanceCounter = "
+ External.NestedFoo.getInstanceCounter());
// External.NestedFoo.methodFoExperiments(); // Ошибка! Ответьте себе почему?!
External.NestedFoo nestedInstance = new External.NestedFoo();
// Вот теперь можно получить доступ к нестатическому члену статического класса:
nestedInstance.methodFoExperiments();
}
}
В свою очередь Nested(static) класс — не совсем прозрачен для внешнего класса. Внешний класс не видит члены Nested(static) класса, без упоминания его имени или объекта. В коде внешнего класса нельзя прямо обратиться к члену вложенного класса.
Соответственно, для обращения к статическим членам вложенного статического класса нужно использовать его имя, а для обращения к НЕстатическим членам вложенного статического класса — нужно использовать имя его экземпляра. При этом, модификаторы доступа не влияют на видимость членов Nested(static) класса, для внешнего класса (private, default (package visible), protected, public).
Код-пример:
public class External {
public static void main(String[] args) {
NestedFoo first = new NestedFoo(); // Две равнозначные строки.
External.NestedFoo second = new External.NestedFoo(); // Только имена ссылок разные.
first.name = "first";
first.number = 42;
second.name = "second";
second.number = Double.POSITIVE_INFINITY;
first.internalNonStatic();
second.internalNonStatic();
NestedFoo.testInstance = null;
NestedFoo.internalStatic();
}
static class NestedFoo {
private String name;
double number;
static External testInstance = new External();
private void internalNonStatic() {
System.out.printf("Internal non-static method. Instance name: %s, instance number: %f\n", name, number);
}
private static void internalStatic() {
System.out.println("Internal static method.\n");
}
}
}
Доступ к вложенному классу и его членам, из других классов, ограничивается модификаторами доступа и уровня.
Вам ответят команда поддержки Хекслета или другие студенты.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт