CodeGym /Blog Java /Random-PL /Klasy anonimowe
Autor
John Selawsky
Senior Java Developer and Tutor at LearningTree

Klasy anonimowe

Opublikowano w grupie Random-PL
Cześć! Podczas dzisiejszej lekcji będziemy nadal omawiać temat klas zagnieżdżonych. Teraz czas na ostatnią grupę: anonimowe klasy wewnętrzne. Wróćmy do naszego diagramu: Zajęcia anonimowe - 2Podobnie jak zajęcia lokalne, o których mówiliśmy w poprzedniej lekcji, zajęcia anonimowe są rodzajem klasy wewnętrznej… Mają też kilka podobieństw i różnic. Ale najpierw przyjrzyjmy się bliżej: dlaczego dokładnie nazywa się ich „anonimowymi”? Aby odpowiedzieć na to pytanie, rozważ prosty przykład. Wyobraź sobie, że mamy podstawowy program, który ciągle działa i coś robi. Chcemy stworzyć system monitoringu dla tego programu, składający się z kilku modułów. Jeden moduł będzie śledził ogólne wskaźniki wydajności i prowadził dziennik. Drugi rejestruje i rejestruje błędy w dzienniku błędów. Trzeci będzie śledzić podejrzaną aktywność, na przykład próby nieautoryzowanego dostępu i inne rzeczy związane z bezpieczeństwem. Ponieważ wszystkie trzy moduły powinny po prostu zaczynać się na początku programu i działać w tle,

public interface MonitoringSystem {
  
   public void startMonitoring();
}
Wdrożą go 3 konkretne klasy:

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!");
   }
}
Wydawałoby się, że wszystko jest w porządku. Mamy dość spójny system składający się z kilku modułów. Każdy z nich ma swoje własne zachowanie. Jeśli potrzebujemy nowych modułów, możemy je dodać, ponieważ mamy interfejs, który jest dość łatwy do wdrożenia. Ale zastanówmy się, jak będzie działał nasz system monitoringu. Zajęcia anonimowe - 3Zasadniczo wystarczy utworzyć 3 obiekty — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule— i wywołać startMonitoring()metodę na każdym z nich. Oznacza to, że wszystko, co musimy zrobić, to utworzyć 3 obiekty i wywołać na nich 1 metodę.

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();
   }
}
Wyjście konsoli:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
I tak niewielkim nakładem pracy napisaliśmy cały system: 3 klasy i jeden interfejs! A wszystko to po to, aby uzyskać 6 linii kodu. Z drugiej strony, jakie mamy opcje? No to nie za fajnie, że napisaliśmy te "jednorazowe" zajęcia. Ale jak możemy to naprawić? Tutaj anonimowe klasy wewnętrzne przychodzą nam na ratunek! Oto jak wyglądają w naszym przypadku:

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();
   }
}
Dowiedzmy się, co się dzieje! Wygląda na to, że tworzymy obiekt interfejsu:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
Ale od dawna wiemy, że nie możemy tworzyć obiektów interfejsu! I tak jest — to niemożliwe. Właściwie to nie to, co robimy. Kiedy piszemy:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
wewnątrz maszyny Java dzieje się:
  1. Tworzona jest nienazwana klasa Java, która implementuje MonitoringSysteminterfejs.
  2. Kiedy kompilator widzi taką klasę, wymaga zaimplementowania wszystkich metod interfejsu MonitoringSystem(robiliśmy to 3 razy).
  3. Tworzony jest jeden obiekt tej klasy. Zwróć uwagę na kod:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
Na końcu jest średnik! Jest tam z jakiegoś powodu. Jednocześnie deklarujemy klasę (używając nawiasów klamrowych) i tworzymy jej instancję (używając ();). Każdy z naszych trzech obiektów nadpisuje startMonitoring()metodę na swój własny sposób. Na koniec po prostu wywołujemy tę metodę na każdym z nich:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Wyjście konsoli:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
Otóż ​​to! Osiągnęliśmy nasz cel: stworzyliśmy trzy MonitoringSystemobiekty, zastąpiliśmy metodę na trzy różne sposoby i trzy razy ją nazwaliśmy. Wszystkie trzy moduły zostały pomyślnie wywołane i działają. Jednocześnie struktura naszego programu stała się znacznie prostsza! W końcu klasy GeneralIndicatorMonitoringModule, ErrorMonitoringModule, i SecurityModulemożna teraz całkowicie usunąć z programu! Po prostu ich nie potrzebujemy — bez nich wykonaliśmy świetną robotę. Jeśli każda z naszych anonimowych klas potrzebuje innego zachowania, np. własnych specyficznych metod, których nie mają inne, możemy je łatwo dodać:

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");
   }
};
Dokumentacja Oracle zawiera dobrą rekomendację : „Użyj [klas anonimowych], jeśli chcesz użyć klasy lokalnej tylko raz”. Klasa anonimowa jest pełnoprawną klasą wewnętrzną. W związku z tym ma dostęp do zmiennych klasy zewnętrznej, w tym zmiennych statycznych i prywatnych:

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;
           }
       };
   }
}
Mają one coś wspólnego z klasami lokalnymi: są widoczne tylko wewnątrz metody, w której zostały zadeklarowane. W powyższym przykładzie wszelkie próby uzyskania dostępu do errorModuleobiektu poza main()metodą zakończą się niepowodzeniem. Jest jeszcze jedno ważne ograniczenie, które klasy anonimowe dziedziczą po swoich „przodkach” (klasach wewnętrznych): klasa anonimowa nie może zawierać statycznych zmiennych i metod . W powyższym przykładzie, jeśli spróbujemy uczynić getCurrentErrorCount()metodę statyczną, kompilator wygeneruje błąd:

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

   return currentErrorCount;
}
Otrzymamy ten sam wynik, jeśli spróbujemy zadeklarować zmienną statyczną:

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!");
   }

};
I nasza dzisiejsza lekcja dobiegła końca! Ale chociaż zbadaliśmy ostatnią grupę klas zagnieżdżonych, nie zakończyliśmy jeszcze tego tematu. Czego jeszcze dowiemy się o klasach zagnieżdżonych? Z pewnością wkrótce się przekonasz! :)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION