En el paradigma de la programación orientada a objetos con Java, el anidamiento de clases es una técnica que permite declarar una clase dentro de los límites de otra. A la clase que contiene se le denomina clase externa, mientras que la clase definida en su interior se conoce como clase interna.
Clases Internas de Miembro
Una clase interna de miembro se declara directamente dentro del cuerpo de la clase externa, al mismo nivel que sus atributos y métodos. Esta arquitectura es ideal para modelar relaciones de composición estricta, donde un objeto carece de sentido sin el contexto de su contenedor. Por ejemplo, un componente de hardware como un procesador está intrínsecamente ligado a una computadora.
Sintaxis básica:
class Computadora {
class Procesador {
// Definición del componente interno
}
}
Reglas de Acceso
- La clase interna tiene acceso directo y sin restricciones a todos los atributos y métodos de la clase externa, incluyendo aquellos marcados como
private. - La clase externa, por el contrario, no puede acceder directamente a los miembros de la clase interna. Para interactuar con ella, la clase externa debe primero instanciar un objeto de la clase interna.
Para crear una instancia de una clase interna desde un contexto estático o externo, se requiere primero una instancia de la clase externa. La sintaxis de instanciación es la siguiente:
NombreClaseExterna.NombreClaseInterna objeto = new NombreClaseExterna().new NombreClaseInterna();
Ejemplo práctico de interacción:
Definición de las clases:
public class Servidor {
private boolean enOperacion = true;
class MonitorDeSalud {
public void verificarEstado() {
// Acceso directo al atributo privado de la clase externa
if (enOperacion) {
System.out.println("El servidor está procesando solicitudes.");
} else {
System.out.println("El servidor está apagado.");
}
}
}
public void apagar() {
this.enOperacion = false;
}
}
Clase de prueba y ejecución:
public class PruebaSistema {
public static void main(String[] args) {
// 1. Instancia de la clase externa
Servidor miServidor = new Servidor();
// 2. Instancia de la clase interna vinculada al objeto externo
Servidor.MonitorDeSalud monitor = miServidor.new MonitorDeSalud();
// 3. Invocación de métodos
monitor.verificarEstado();
miServidor.apagar();
monitor.verificarEstado();
}
}
Salida en consola:
El servidor está procesando solicitudes.
El servidor está apagado.
Clases Internas Anónimas
Una clase interna anónima es una declaración e instanciación simultánea de una clase que no posee un identificador formal. Generalmente, representa un objeto anónimo que hereda de una clase base o implementa una interfaz específica.
En el desarrollo de software, este es el tipo de clase interna más utilizado. Tradicionalmente, utilizar una interfaz requiere un flujo de trabajo de cuatro pasos:
- Declarar una nueva clase que implemente la interfaz.
- Sobrescribir los métodos abstractos definidos.
- Crear un objeto de esta nueva clase.
- Llamar al método implementado.
Si el objetivo final es únicamente ejecutar la lógica del método una sola vez, las clases anónimas permiten condensar todo este proceso en un único bloque de código.
Requisitos y Formato
La condición fundamental para emplear una clase anónima es que debe extender una superclase existente o implementar una interfaz. Su estructura básica se define así:
new NombreDeInterfazOClase() {
@Override
public void metodoAbstracto() {
// Lógica de implementación
}
};
Implementación práctica:
Declaración de la interfaz base:
public interface ExportadorDeDatos {
void exportar();
}
Creación de la clase aónima y ejecución:
public class AplicacionDeExportacion {
public static void main(String[] args) {
/*
El lado derecho crea el objeto anónimo implementando la interfaz.
El lado izquierdo utiliza polimorfismo para referenciar el objeto.
*/
ExportadorDeDatos exportadorCsv = new ExportadorDeDatos() {
@Override
public void exportar() {
System.out.println("Generando archivo CSV...");
}
};
exportadorCsv.exportar();
}
}
Paso de Clases Anónimas como Parámetros
Un caso de uso común en el diseño de APIs es recibir interfaces o clases abstractas como argumentos en métodos. Las clases anónimas permiten inyectar comportamientos específicos directamente en la llamada al método.
Asignación previa a variable:
public class ProcesadorDeReportes {
public static void main(String[] args) {
ExportadorDeDatos exportadorJson = new ExportadorDeDatos() {
@Override
public void exportar() {
System.out.println("Serializando datos a JSON...");
}
};
generarReporte(exportadorJson);
}
public static void generarReporte(ExportadorDeDatos formato) {
formato.exportar();
}
}
Optimización mediante instanciación directa en la firma del método:
public class ProcesadorDeReportesOptimizado {
public static void main(String[] args) {
// El objeto anónimo se crea y se pasa como argumento en una sola instrucción
generarReporte(new ExportadorDeDatos() {
@Override
public void exportar() {
System.out.println("Renderizando reporte en formato XML...");
}
});
}
public static void generarReporte(ExportadorDeDatos formato) {
formato.exportar();
}
}