🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!
Продолжаем изучать тему вложенных классов в Java. В этой статье рассмотрим статические вложенные классы (static nested classes).

Чем они отличаются от других классов?
При объявлении такого класса используется ключевое слово static:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}Run Code
В этом примере у нас есть внешний класс Boeing737, который представляет самолет данной модели. У него есть конструктор с одним параметром — годом выпуска(int manufactureYear).
Есть также одна статическая переменная — максимальное количество пассажиров(int maxPassengersCount). Для всех самолетов этой модели это число одинаковое, поэтому не нужно хранить отдельное значение в каждом объекте. Кроме того, у него есть статический вложенный класс — Drawing (представляющий инженерные чертежи самолета).
Мы используем этот класс для инкапсуляции всей официальной информации о самолете. В нашем примере мы оставили только год выпуска, но на практике в этом классе может храниться куда больше данных.

Создание вложенного класса улучшает инкапсуляцию и делает абстракцию более реалистичной. И в чем же разница между статическими и нестатическими вложенными классами?
1. Объект статического класса Drawing не хранит ссылку на конкретный экземпляр внешнего класса.
Вот пример с велосипедом:
public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
}Run CodeВ данном случае, каждый экземпляр внутреннего (inner) класса Handlebar неявно хранит ссылку на объект внешнего класса Bicycle.
Без объекта внешнего класса объект внутреннего класса просто не может существовать.
Со статическими вложенными классами ситуация иная — их экземпляры вполне себе могут жить отдельно.
В этом смысле статические классы более независимые, чем нестатические. Единственное, что нужно помнить, это то, что при создании такого объекта необходимо указать имя внешнего класса:
public class Main {
public static void main(String[] args) {
Boeing737.Drawing drawing1 = new Boeing737.Drawing();
Boeing737.Drawing drawing2 = new Boeing737.Drawing();
}
}Run CodeПочему же мы сделали класс Drawing статическим?
Концепция инженерного чертежа не привязана жестко к конкретному самолету.
Инженерный чертеж имеет смысл сам по себе. Например, он может быть полезен инженерам, планирующим техническое обслуживание самолетов. Для этого не нужно иметь конкретный самолет — он может находиться где угодно.
Необходим только сам чертеж. Более того, все самолеты одной модели будут иметь одинаковый чертеж. Именно поэтому объект Drawing не нуждается в ссылке на конкретный объект самолета.
2. Различный доступ к переменным и методам внешнего класса.
Статический вложенный класс может обращаться только к статическим полям внешнего класса. В нашем примере класс Drawing имеет метод getMaxPassengersCount(), который возвращает значение статической переменной maxPassengersCount из внешнего класса.
Однако мы не можем создать метод getManufactureYear() в классе Drawing, чтобы вернуть значение manufactureYear. Дело в том, что переменная manufactureYear является нестатической, а значит, должна принадлежать конкретному экземпляру Boeing737. А как мы уже выяснили, у статических вложенных классов объект внешнего класса может вообще отсутствовать. Отсюда и ограничение 🙂
При этом совершенно неважно, какой модификатор доступа имеет статическая переменная во внешнем классе. Даже если она private, статический вложенный класс все равно получит к ней доступ.
Все вышесказанное относится не только к статическим переменным, но и к статическим методам.
ВАЖНО! В объявлении внутреннего класса ключевое слово static не означает, что можно создать только один объект. Не путайте объекты и переменные.
Если речь идет о статических переменных, то да, у нас будет единственный экземпляр переменной на весь класс, например, maxPassangersCount.
Но если static применяется к вложенному классу, это означает лишь то, что его объекты не содержат ссылок на объекты внешнего класса. А создать таких объектов можно сколько угодно:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
private int id;
public Drawing(int id) {
this.id = id;
}
public static int getPassengersCount() {
return maxPassengersCount;
}
@Override
public String toString() {
return "Drawing{" +
"id=" + id +
'}';
}
public static void main(String[] args) {
for (int i = 1; i < 6; i++) {
Boeing737.Drawing drawing = new Boeing737.Drawing(i);
System.out.println(drawing);
}
}
}
}Run CodeМы объявили метод main() непосредственно во вложенном классе (без особой необходимости — просто чтобы показать, что так можно) и создали 5 объектов Drawing. При этом у нас нет ни одного объекта внешнего класса.
Как видите, это не вызвало никаких проблем 🙂
Консольный вывод:
Drawing{id=1}
Drawing{id=2}
Drawing{id=3}
Drawing{id=4}
Drawing{id=5}
На этом разбор закончен.
Но если вдруг остались вопросы, вот ссылка на раздел о статических вложенных классах в документации Oracle.
Перевод статьи «Static nested classes».
