здрасти В днешния урок ще продължим да разглеждаме темата за вложените класове. Сега е време за последната група: анонимни вътрешни класове. Да се ​​върнем към нашата диаграма: Анонимни часове – 2 брПодобно на локалните класове, за които говорихме в миналия урок, анонимните класове са вид вътрешни класове... Те също имат няколко прorки и разлики. Но първо, нека се потопим в: защо точно те се наричат ​​„анонимни“? За да отговорите на това, разгледайте един прост пример. Представете си, че имаме базова програма, която постоянно работи и прави нещо. Искаме да създадем система за мониторинг на тази програма, съставена от няколко модула. Един модул ще проследява общите показатели за ефективност и ще поддържа дневник. Вторият ще регистрира и записва грешки в регистър на грешките. Третият ще проследява подозрителна дейност: например опити за неоторизиран достъп и други неща, свързани със сигурността. Тъй като и трите модула трябва по същество просто да стартират в началото на програмата и да работят във фонов режим,

public interface MonitoringSystem {
  
   public void startMonitoring();
}
3 конкретни класа ще го реализират:

public class GeneralIndicatorMonitoringModule implements MonitoringSystem {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor security!");
   }
}
Изглежда, че всичко е наред. Имаме доста стройна система, съставена от няколко модула. Всеки от тях има свое поведение. Ако имаме нужда от нови модули, можем да ги добавим, защото имаме интерфейс, който е доста лесен за изпълнение. Но нека помислим How ще работи нашата система за наблюдение. Анонимни часове – 3 брПо принцип просто трябва да създадем 3 обекта — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule— и да извикаме startMonitoring()метода на всеки от тях. Тоест, всичко, което трябва да направим, е да създадем 3 обекта и да извикаме 1 метод върху тях.

public class Main {

   public static void main(String[] args) {

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

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Конзолен изход:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
И с толкова малко работа, ние написахме цялата система: 3 класа и един интерфейс! И всичко това, за да постигнете 6 реда code. От друга страна, Howви са нашите възможности? Е, не е много готино, че сме написали тези "еднократни" часове. Но How можем да поправим това? Тук анонимните вътрешни класове ни идват на помощ! Ето How изглеждат в нашия случай:

public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor general indicators!");
           }
       };

       

MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor security!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Нека да разберем Howво става! Изглежда, че създаваме интерфейсен обект:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
Но отдавна знаем, че не можем да създаваме интерфейсни обекти! И това е така - невъзможно е. Всъщност ние не правим това. Когато пишем:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
в Java машината се случва следното:
  1. Създава се неназован Java клас, който реализира MonitoringSystemинтерфейса.
  2. Когато компилаторът види такъв клас, той изисква да имплементирате всички методи на интерфейса MonitoringSystem(направихме това 3 пъти).
  3. Създаден е един обект от този клас. Обърнете внимание на codeа:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
В края има точка и запетая! Има причина. Едновременно декларираме класа (използвайки фигурни скоби) и създаваме негов екземпляр (използвайки ();). Всеки от нашите три обекта отменя startMonitoring()метода по свой начин. И накрая, ние просто извикваме този метод на всеки от тях:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Конзолен изход:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
Това е! Постигнахме целта си: създадохме три MonitoringSystemобекта, отменихме метод по три различни начина и го извикахме три пъти. И трите модула са извикани успешно и работят. В същото време структурата на нашата програма стана много по-проста! В края на краищата класовете GeneralIndicatorMonitoringModule, ErrorMonitoringModule, и SecurityModuleвече могат да бъдат напълно премахнати от програмата! Просто нямаме нужда от тях — свършихме страхотна работа и без тях. Ако всеки от нашите анонимни класове се нуждае от различно поведение, например собствени специфични методи, които другите нямат, можем лесно да ги добавим:

MonitoringSystem generalModule = new MonitoringSystem() {
  
   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
  
   public void someSpecificMethod() {

       System.out.println("Specific method only for the first module");
   }
};
Документацията на Oracle дава добра препоръка : "Използвайте [анонимни класове], ако трябва да използвате локален клас само веднъж." Анонимният клас е пълноценен вътрешен клас. Съответно, той има достъп до променливите на външния клас, включително статични и частни променливи:

public class Main {

   private static int currentErrorCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {
          
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }

           public int getCurrentErrorCount() {

               return currentErrorCount;
           }
       };
   }
}
Те имат нещо общо с локалните класове: те са видими само вътре в метода, в който са декларирани. В горния пример всички опити за достъп до errorModuleобекта извън main()метода ще бъдат неуспешни. И има още едно важно ограничение, което анонимните класове наследяват от своите „предци“ (вътрешни класове): анонимният клас не може да съдържа статични променливи и методи . В горния пример, ако се опитаме да направим getCurrentErrorCount()метода статичен, компилаторът ще генерира грешка:

// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {

   return currentErrorCount;
}
Получаваме същия резултат, ако се опитаме да декларираме статична променлива:

MonitoringSystem errorModule = new MonitoringSystem() {

   // Error! Inner classes cannot have static declarations!
   static int staticInt = 10;

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }

};
И нашият урок днес приключи! Но въпреки че проучихме последната група от вложени класове, все още не сме завършor тази тема. Какво повече ще научим за вложените класове? Със сигурност ще разберете скоро! :)