CodeGym /Blog Java /Random-ES /Clases anónimas
Autor
John Selawsky
Senior Java Developer and Tutor at LearningTree

Clases anónimas

Publicado en el grupo Random-ES
¡Hola! En la lección de hoy, continuaremos examinando el tema de las clases anidadas. Ahora es el momento del último grupo: clases internas anónimas. Volvamos a nuestro diagrama: Clases anónimas - 2Al igual que las clases locales de las que hablamos en la última lección, las clases anónimas son una especie de clase interna... También tienen varias similitudes y diferencias. Pero primero, profundicemos: ¿por qué exactamente se les llama "anónimos"? Para responder a esto, considere un ejemplo simple. Imagine que tenemos un programa básico que se ejecuta constantemente y hace algo. Queremos crear un sistema de monitoreo para este programa, compuesto por varios módulos. Un módulo hará un seguimiento de los indicadores generales de desempeño y mantendrá un registro. El segundo registrará y registrará los errores en un registro de errores. El tercero rastreará actividades sospechosas: por ejemplo, intentos de acceso no autorizado y otras cosas relacionadas con la seguridad. Debido a que los tres módulos deberían, en esencia, simplemente comenzar al principio del programa y ejecutarse en segundo plano,

public interface MonitoringSystem {
  
   public void startMonitoring();
}
3 clases concretas lo implementarán:

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!");
   }
}
Parece que todo está en orden. Tenemos un sistema bastante coherente formado por varios módulos. Cada uno de ellos tiene su propio comportamiento. Si necesitamos nuevos módulos, podemos agregarlos, porque tenemos una interfaz que es bastante fácil de implementar. Pero pensemos en cómo funcionará nuestro sistema de monitoreo. Clases anónimas - 3Básicamente, solo necesitamos crear 3 objetos — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule— y llamar al startMonitoring()método en cada uno de ellos. Es decir, todo lo que tenemos que hacer es crear 3 objetos y llamar a 1 método sobre ellos.

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();
   }
}
Salida de la consola:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
Y con tan poco trabajo, hemos escrito todo el sistema: ¡3 clases y una interfaz! Y todo esto para lograr 6 líneas de código. Por otro lado, ¿cuáles son nuestras opciones? Bueno, no es muy bueno que escribimos estas clases "únicas". Pero, ¿cómo podemos arreglar esto? ¡ Aquí las clases internas anónimas vienen a nuestro rescate! Así es como se ven en nuestro 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();
   }
}
¡Averigüemos qué está pasando! Parece que estamos creando un objeto de interfaz:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
¡Pero sabemos desde hace mucho tiempo que no podemos crear objetos de interfaz! Y así es, es imposible. De hecho, eso no es lo que estamos haciendo. Cuando escribimos:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
lo siguiente sucede dentro de la máquina Java:
  1. Se crea una clase Java sin nombre que implementa la MonitoringSysteminterfaz.
  2. Cuando el compilador ve una clase de este tipo, requiere que implementes todos los métodos de la MonitoringSysteminterfaz (lo hicimos 3 veces).
  3. Se crea un objeto de esta clase. Presta atención al código:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
¡Hay un punto y coma al final! Está ahí por una razón. Declaramos la clase simultáneamente (usando llaves) y creamos una instancia de ella (usando ();). Cada uno de nuestros tres objetos anula el startMonitoring()método a su manera. Finalmente, simplemente llamamos a este método en cada uno de ellos:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Salida de la consola:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
¡Eso es todo! Logramos nuestro objetivo: creamos tres MonitoringSystemobjetos, anulamos un método de tres maneras diferentes y lo llamamos tres veces. Los tres módulos se han llamado con éxito y se están ejecutando. ¡Al mismo tiempo, la estructura de nuestro programa se ha vuelto mucho más simple! ¡Después de todo, las clases GeneralIndicatorMonitoringModule, ErrorMonitoringModuley SecurityModuleahora se pueden eliminar por completo del programa! Simplemente no los necesitamos, hicimos un gran trabajo sin ellos. Si cada una de nuestras clases anónimas necesita un comportamiento diferente, por ejemplo, sus propios métodos específicos que los demás no tienen, podemos agregarlos fácilmente:

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 documentación de Oracle proporciona una buena recomendación : "Use [clases anónimas] si necesita usar una clase local solo una vez". Una clase anónima es una clase interna completa. En consecuencia, tiene acceso a las variables de la clase externa, incluidas variables estáticas y privadas:

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;
           }
       };
   }
}
Tienen algo en común con las clases locales: son visibles solo dentro del método en el que se declaran. En el ejemplo anterior, cualquier intento de acceder al errorModuleobjeto fuera del main()método fallará. Y hay una limitación más importante que las clases anónimas heredan de sus "ancestros" (clases internas): una clase anónima no puede contener variables y métodos estáticos . En el ejemplo anterior, si tratamos de hacer que el getCurrentErrorCount()método sea estático, el compilador generará un error:

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

   return currentErrorCount;
}
Obtenemos el mismo resultado si intentamos declarar una variable estática:

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

};
¡Y nuestra lección de hoy ha llegado a su fin! Pero aunque hemos investigado el último grupo de clases anidadas, aún no hemos terminado este tema. ¿Qué más aprenderemos sobre las clases anidadas? ¡Seguro que pronto lo descubrirás! :)
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION