CodeGym /Java Blog /Random-IT /Classi anonime
John Squirrels
Livello 41
San Francisco

Classi anonime

Pubblicato nel gruppo Random-IT
CIAO! Nella lezione di oggi continueremo ad esaminare l'argomento delle classi nidificate. Ora è il momento dell'ultimo gruppo: classi interne anonime. Torniamo al nostro diagramma: Classi anonime - 2Come le classi locali di cui abbiamo parlato nell'ultima lezione, le classi anonime sono una sorta di classe interna... Hanno anche molte somiglianze e differenze. Ma prima, tuffiamoci: perché si chiamano esattamente "anonimi"? Per rispondere a questa domanda, considera un semplice esempio. Immagina di avere un programma di base che è costantemente in esecuzione e fa qualcosa. Vogliamo creare un sistema di monitoraggio per questo programma, composto da diversi moduli. Un modulo monitorerà gli indicatori generali delle prestazioni e manterrà un registro. Il secondo registrerà e registrerà gli errori in un registro degli errori. Il terzo terrà traccia delle attività sospette: ad esempio, tentativi di accesso non autorizzato e altre cose relative alla sicurezza. Poiché tutti e tre i moduli dovrebbero, in sostanza, iniziare semplicemente all'inizio del programma ed essere eseguiti in background,

public interface MonitoringSystem {
  
   public void startMonitoring();
}
3 classi concrete lo implementeranno:

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!");
   }
}
Sembrerebbe che tutto sia in ordine. Abbiamo un sistema piuttosto coerente composto da diversi moduli. Ognuno di loro ha il suo comportamento. Se abbiamo bisogno di nuovi moduli, possiamo aggiungerli, perché abbiamo un'interfaccia abbastanza facile da implementare. Ma pensiamo a come funzionerà il nostro sistema di monitoraggio. Classi anonime - 3Fondamentalmente, dobbiamo solo creare 3 oggetti — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule— e chiamare il startMonitoring()metodo su ciascuno di essi. Cioè, tutto ciò che dobbiamo fare è creare 3 oggetti e chiamare 1 metodo su di essi.

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();
   }
}
Uscita console:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
E con così poco lavoro, abbiamo scritto l'intero sistema: 3 classi e un'interfaccia! E tutto questo per ottenere 6 righe di codice. D'altra parte, quali sono le nostre opzioni? Beh, non è molto bello che abbiamo scritto queste lezioni "una tantum". Ma come possiamo risolvere questo problema? Ecco che le classi interne anonime vengono in nostro soccorso! Ecco come appaiono nel nostro caso:

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();
   }
}
Scopriamo cosa sta succedendo! Sembra che stiamo creando un oggetto interfaccia:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
Ma sappiamo da tempo che non possiamo creare oggetti di interfaccia! E così è: è impossibile. In effetti, non è quello che stiamo facendo. Quando scriviamo:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
quanto segue accade all'interno della macchina Java:
  1. Viene creata una classe Java senza nome che implementa l' MonitoringSysteminterfaccia.
  2. Quando il compilatore vede una tale classe, richiede di implementare tutti i metodi dell'interfaccia MonitoringSystem(l'abbiamo fatto 3 volte).
  3. Viene creato un oggetto di questa classe. Prestare attenzione al codice:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
C'è un punto e virgola alla fine! È lì per un motivo. Contemporaneamente dichiariamo la classe (usando le parentesi graffe) e ne creiamo un'istanza (usando ();). Ciascuno dei nostri tre oggetti sovrascrive il startMonitoring()metodo a modo suo. Infine, chiamiamo semplicemente questo metodo su ciascuno di essi:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Uscita console:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
Questo è tutto! Abbiamo raggiunto il nostro obiettivo: abbiamo creato tre MonitoringSystemoggetti, scavalcato un metodo in tre modi diversi e chiamato tre volte. Tutti e tre i moduli sono stati richiamati correttamente e sono in esecuzione. Allo stesso tempo, la struttura del nostro programma è diventata molto più semplice! Dopotutto, le GeneralIndicatorMonitoringModuleclassi ErrorMonitoringModule, e SecurityModuleora possono essere completamente rimosse dal programma! Semplicemente non ne abbiamo bisogno: abbiamo fatto un ottimo lavoro senza di loro. Se ciascuna delle nostre classi anonime necessita di un comportamento diverso, ad esempio i propri metodi specifici che le altre non hanno, possiamo aggiungerli facilmente:

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");
   }
};
La documentazione Oracle fornisce una buona raccomandazione : "Usa [classi anonime] se hai bisogno di usare una classe locale solo una volta". Una classe anonima è una classe interna a tutti gli effetti. Di conseguenza, ha accesso alle variabili della classe esterna, comprese le variabili statiche e private:

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;
           }
       };
   }
}
Hanno qualcosa in comune con le classi locali: sono visibili solo all'interno del metodo in cui sono dichiarate. Nell'esempio precedente, qualsiasi tentativo di accedere all'oggetto errorModuleal di fuori del main()metodo fallirà. E c'è un'altra limitazione importante che le classi anonime ereditano dai loro "antenati" (classi interne): una classe anonima non può contenere variabili e metodi statici . Nell'esempio sopra, se proviamo a rendere getCurrentErrorCount()statico il metodo, il compilatore genererà un errore:

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

   return currentErrorCount;
}
Otteniamo lo stesso risultato se proviamo a dichiarare una variabile statica:

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

};
E la nostra lezione di oggi è giunta al termine! Ma anche se abbiamo esaminato l'ultimo gruppo di classi nidificate, non abbiamo ancora terminato questo argomento. Cos'altro impareremo sulle classi nidificate? Lo scoprirete sicuramente presto! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION