JavaRush /Java блог /Random UA /Статичні вкладені класи

Статичні вкладені класи

Стаття з групи Random UA
Вітання! Ми продовжуємо вивчати тему вкладених класів у Java. На минулому занятті ми поговорабо про нестатичні внутрішні класи (non-static nested classes) або, як їх ще називають, внутрішні класи. Статичні вкладені класи - 2Сьогодні перейдемо до іншої групи та розглянемо докладніше статичні вкладені класи (static nested classes). Статичні вкладені класи - 3Чим вони відрізняються від інших груп? При оголошенні такого класу ми використовуємо ключове слово 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;
       }
   }
}
Статичні вкладені класи - 4У цьому прикладі ми маємо зовнішній клас Boeing737, який створює літак цієї моделі. А в нього конструктор з одним параметром: роком випуску ( int manufactureYear). Також є одна статична змінна int maxPassengersCount– максимальна кількість пасажирів. Воно буде однаковим у всіх літаків однієї моделі, тому нам достатньо одного екземпляра. Крім того, він має статичний внутрішній клас Drawing— креслення літака. У цьому класі ми можемо інкапсулювати всю службову інформацію про літак. У нашому прикладі для простоти ми обмежабо її роком випуску, але вона може містити багато іншої інформації. Статичні вкладені класи - 5Як ми й казали у минулій лекції, створення такого вкладеного класу підвищує інкапсуляцію та сприяє більш реалістичній абстракції. У чому ж відмінність між статичним та нестатичним вкладеними класами? 1. Об'єкт статичного класу 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в оголошенні внутрішнього класу не означає, що можна створити лише один об'єкт. Не плутай об'єкти зі змінними. Якщо ми говоримо про статичні змінні — так, статична змінна класу, наприклад, 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);
           }
       }
   }
}
Ми оголосабо метод main()прямо у вкладеному класі (особливих причин для цього немає — просто щоб ти знав, що так можна), і створабо 5 об'єктів Drawing. При тому, що жодного об'єкта зовнішнього класу ми не маємо. Як бачиш, жодних проблем не виникло :) Висновок у консоль:

Drawing{id=1}
Drawing{id=2}
Drawing{id=3}
Drawing{id=4}
Drawing{id=5}
На цьому наше заняття добігло кінця! Про всяк випадок залишу тобі посилання на розділ про них у документації Oracle . Шануй, якщо раптом залишабося неясні моменти. А тепер саме час вирішити кілька завдань! :)
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ