Привіт! Ми продовжуємо вивчати тему вкладених класів (nested classes) в Java. На минулому занятті ми поговорили про нестатичні внутрішні класи (non-static nested classes) або, як їх ще називають, внутрішні класи.
Сьогодні перейдемо до іншої групи і розглянемо детальніше статичні вкладені класи (static nested classes).
Чим вони відрізняються від інших груп?
При оголошенні такого класу ми використовуємо вже знайоме тобі ключове слово static:
У цьому прикладі у нас є зовнішній клас
Як ми й говорили на минулій лекції, створення такого вкладеного класу підвищує інкапсуляцію і сприяє більш реалістичній абстракції.
У чому ж різниця між статичним і нестатичним вкладеними класами?
1. Об'єкт статичного класу


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;
}
}
}

Boeing737
, який створює літак цієї моделі. А у нього — конструктор з одним параметром: роком випуску (int manufactureYear
).
Також є одна статична змінна int maxPassengersCount
— максимальна кількість пасажирів. Вона буде однаковою у всіх літаків однієї моделі, тому нам достатньо одного екземпляра. Крім того, у нього є статичний внутрішній клас Drawing
— креслення літака.
У цьому класі ми можемо інкапсулювати всю службову інформацію про літак. У нашому прикладі для простоти ми її обмежили роком випуску, але вона може містити багато іншої інформації.

Drawing
не зберігає посилання на конкретний екземпляр зовнішнього класу.
Згадай приклад з минулої лекції з велосипедом:
public class Bicycle {
private String model;
private int mawWeight;
public Bicycle(String model, int mawWeight) {
this.model = model;
this.mawWeight = mawWeight;
}
public void start() {
System.out.println("Поїхали!");
}
public class SteeringWheel {
public void right() {
System.out.println("Кермо вправо!");
}
public void left() {
System.out.println("Кермо вліво!");
}
}
}
Там ми говорили про те, що в кожен екземпляр внутрішнього класу SteeringWheel
(кермо) непомітно для нас передається посилання на об'єкт зовнішнього класу Bicycle
(велосипед).
Без об'єкта зовнішнього класу об'єкт внутрішнього просто не міг існувати.
Для статичних вкладених класів це не так. Об'єкт статичного вкладеного класу цілком може існувати сам по собі.
У цьому плані статичні класи більш «незалежні», ніж нестатичні.
Єдиний момент — при створенні такого об'єкта необхідно вказувати назву зовнішнього класу:
public class Main {
public static void main(String[] args) {
Boeing737.Drawing drawing1 = new Boeing737.Drawing();
Boeing737.Drawing drawing2 = new Boeing737.Drawing();
}
}
Чому ми зробили клас Drawing
статичним, а на минулій лекції клас Seat
(сидіння велосипеда) був нестатичним?
Як і минулого разу, давай додамо трохи «філософії» для розуміння прикладу :)
На відміну від сидіння велосипеда, сутність креслення не прив'язана так жорстко до сутності літака.
Окремий об'єкт сидіння, без велосипеда, найчастіше буде позбавлений сенсу (хоча і не завжди — ми говорили про це на минулому занятті).
Сутність креслення має сенс сама по собі. Наприклад, він може стати у пригоді інженерам, які планують ремонт літака. Сам літак для планування їм не потрібен, і може знаходитися де завгодно — достатньо просто креслення.
Крім того, для всіх літаків однієї моделі креслення все одно буде однаковим, такої жорсткої прив'язки, як у сидіння з велосипедом, немає. Тому й посилання на конкретний об'єкт літака об'єкту Drawing
не потрібне.
2. Різний доступ до змінних і методів зовнішнього класу.
Статичний вкладений клас може звертатися тільки до статичних полів зовнішнього класу.
У нашому прикладі в класі Drawing
є метод getMaxPassengersCount()
, який повертає значення статичної змінної maxPassengersCount
із зовнішнього класу.
Проте ми не можемо створити метод getManufactureYear()
у Drawing
для повернення значення manufactureYear
. Адже змінна manufactureYear
— нестатична, а значить, повинна належати конкретному екземпляру Boeing737
. А як ми вже з'ясували, у випадку зі статичними вкладеними класами об'єкт зовнішнього класу запросто може бути відсутнім. Звідси й обмеження :)
При цьому неважливо, який модифікатор доступу має статична змінна у зовнішньому класі. Навіть якщо це private
, доступ із статичного вкладеного класу все одно буде.
Все вищесказане стосується не лише доступу до статичних змінних, але й до статичних методів.
ВАЖЛИВО!
Слово static
в оголошенні внутрішнього класу не означає, що можна створити всього один об'єкт. Не плутай об'єкти зі змінними.
Якщо ми говоримо про статичні змінні — так, статична змінна класу, наприклад, maxPassengersCount
, існує в єдиному екземплярі.
Але стосовно вкладеного класу 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);
}
}
}
}
Ми оголосили метод main()
прямо у вкладеному класі (особливої причини для цього немає — просто щоб ти знав, що так можна), і створили 5 об'єктів Drawing
. При тому, що жодного об'єкта зовнішнього класу у нас немає.
Як бачиш, жодних проблем не виникло :)
Вивід у консоль:
Drawing{id=1}
Drawing{id=2}
Drawing{id=3}
Drawing{id=4}
Drawing{id=5}
На цьому наше заняття завершено!
На всяк випадок залишу тобі посилання на розділ про них в документації Oracle. Почитай, якщо раптом залишилися незрозумілі моменти.
А тепер саме час вирішити пару задач! :)
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ