JavaRush /Java блог /Random UA /Анонімні класи в Java

Анонімні класи в Java

Стаття з групи Random UA
Вітання! На сьогоднішньому занятті ми продовжимо розглядати тему вкладених класів. Настала черга останньої групи — анонімних внутрішніх класів Java. Давай повернемося до нашої схеми: Анонімні класи - 2Як і локальні класи, про які ми говорабо в минулій лекції, анонімні підвид внутрішніх класів. У них також є кілька подібностей та відмінностей між собою. Але спочатку давай розберемося: а чому вони, власне, називаються «анонімними»? Для цього розглянемо найпростіший приклад. Уяви, що ми маємо основну програму, яка постійно працює і щось робить. Ми хочемо створити для цієї програми систему моніторингу із кількох модулів. Один модуль відстежуватиме загальні показники роботи та вестиме лог, другий — фіксуватиме та реєструватиме помилки в журналі помилок, третій — відстежуватиме підозрілу активність: наприклад, спроби несанкціонованого доступу та інші пов'язані з безпекою речі. Оскільки всі три модулі повинні, по суті, просто стартувати на початку програми та працювати у фоновому режимі,
public interface MonitoringSystem {

   public void startMonitoring();
}
Його імплементуватимуть 3 конкретні класи:
public class GeneralIndicatorsMonitoringModule implements MonitoringSystem {

@Override
   public void startMonitoring() {
       System.out.println("Моніторинг загальних показників стартував!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Моніторинг відстеження помилок стартував!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Моніторинг безпеки стартував!");
   }
}
Здавалося б, все гаразд. У нас є досить виразна система з кількох модулів. Кожен з них має власну поведінку. Якщо нам знадобляться нові модулі, ми зможемо їх додати, адже ми маємо інтерфейс, який досить легко імплементувати. Але давай подумаємо про те, як працюватиме наша система моніторингу. Анонімні класи - 3По суті, ми повинні просто створити три об'єкти — GeneralIndicatorsMonitoringModule, ErrorMonitoringModule, SecurityModule— і викликати метод startMonitoring()у кожного з них. Тобто все, що потрібно зробити — створити 3 об'єкти та викликати у них 1 метод.
public class Main {

   public static void main(String[] args) {

       GeneralIndicatorsMonitoringModule generalModule = new GeneralIndicatorsMonitoringModule();
       ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
       SecurityModule securityModule = new SecurityModule();

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Виведення в консоль:

Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
І для такої невеликої роботи ми написали цілу систему: 3 класи та один інтерфейс! І все це заради 6 рядків коду. З іншого боку, які варіанти? Так, не дуже добре, що ми понаписали таких ось «одноразових» класів. Але як ми можемо це виправити? Тут нам і приходять на допомогу анонімні внутрішні класи ! Ось як вони виглядають у нашому випадку:
public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Моніторинг загальних показників стартував!");
           }
       };



           MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Моніторинг відстеження помилок стартував!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Моніторинг безпеки стартував!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Давай розбиратись, що тут відбувається! Виглядає так, ніби ми створюємо об'єкт інтерфейсу:
MonitoringSystem generalModule = new MonitoringSystem() {

@Override
   public void startMonitoring() {
       System.out.println("Моніторинг загальних показників стартував!");
   }
};
Але ж ми давно знаємо, що створювати об'єкти інтерфейсів не можна! Так і є, не можна. Насправді ми цього не робимо. У той момент, коли ми пишемо:
MonitoringSystem generalModule = new MonitoringSystem() {

};
всередині Java-машини відбувається таке:
  1. Створюється безіменний Java-клас, що реалізує інтерфейс MonitoringSystem.
  2. Компілятор, побачивши такий клас, вимагає від тебе реалізувати всі методи інтерфейсу MonitoringSystem(ми це зробабо 3 рази).
  3. Створюється об'єкт цього класу. Зверніть увагу на код:
MonitoringSystem generalModule = new MonitoringSystem() {

};
Наприкінці стоїть крапка з комою! Вона стоїть там не так. Ми одночасно оголошуємо клас (за допомогою фігурних дужок) та створюємо його об'єкт за допомогою (); Кожен із наших трьох об'єктів перевизначив метод startMonitoring()по-своєму. Насамкінець ми просто викликаємо цей метод у кожного з них:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Виведення в консоль:

Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
От і все! Ми виконали своє завдання: створабо три об'єкти MonitoringSystem, перевизначабо його трьома різними способами та викликали тричі. Всі три модулі успішно запущені та працюють. При цьому структура нашої програми стала набагато простішою! Адже класи , GeneralIndicatorsMonitoringModuleтепер взагалі можна видалити з програми! Вони нам просто не потрібні – ми чудово впоралися і без них. Якщо кожному з наших анонімних класів-модулів знадобиться якась поведінка, що відрізняється, свої специфічні методи, яких немає в інших, ми легко можемо дописати їх: ErrorMonitoringModuleSecurityModule
MonitoringSystem generalModule = new MonitoringSystem() {

   @Override
   public void startMonitoring() {
       System.out.println("Моніторинг загальних показників стартував!");
   }

   public void someSpecificMethod() {

       System.out.println("Специфічний метод лише для першого модуля");
   }
};
У документації Oracle наведено хорошу рекомендацію : «Застосовуйте анонімні класи, якщо вам потрібен локальний клас для одноразового використання». Анонімний клас – це повноцінний внутрішній клас. Тому він має доступ до змінних зовнішнього класу, у тому числі до статичних і приватних:
public class Main {

   private static int currentErrorsCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {

           @Override
           public void startMonitoring() {
               System.out.println("Моніторинг відстеження помилок стартував!");
           }

           public int getCurrentErrorsCount() {

               return currentErrorsCount;
           }
       };
   }
}
Є в них дещо спільне і з локальними класами: вони помітні лише всередині того методу, в якому визначено. У прикладі вище будь-які спроби звернутися до об'єкта errorModuleза межами методу main()будуть невдалими. І ще одне важливе обмеження, яке дісталося анонімним класам від їхніх «предків» — внутрішніх класів: анонімний клас не може містити статичні змінні та методи . Якщо спробуємо зробити метод getCurrentErrorsCount()із прикладу вище статичним, компілятор викине помилку:
//помилка! Inner classes cannot have static declarations
public static int getCurrentErrorsCount() {

   return currentErrorsCount;
}
Той самий результат ми отримаємо, якщо спробуємо оголосити статичну змінну:
MonitoringSystem errorModule = new MonitoringSystem() {

   //помилка! Inner classes може не мати static declarations!
   static int staticInt = 10;

   @Override
   public void startMonitoring() {
       System.out.println("Моніторинг відстеження помилок стартував!");
   }

};
Насамкінець можу порекомендувати тобі відмінне відео на тему анонімних класів, де ця тема пояснюється максимально просто і зрозуміло :)
А наше сьогоднішнє заняття добігло кінця! І хоча ми розібрали останню групу вкладених класів, із цією темою ми ще не закінчабо. Що ж ми вивчатимемо по вкладених класах далі? Скоро ти обов'язково дізнаєшся! :)
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ