CodeGym /Cursos /JAVA 25 SELF /Clases anónimas

Clases anónimas

JAVA 25 SELF
Nivel 16 , Lección 2
Disponible

1. Introducción a las clases anónimas

Imagina que tienes una clase Animal que describe cómo se comporta un animal. Esta clase tiene un método say() que imprime "El animal emite un sonido". Necesitas crear un objeto que se comporte como un perro e imprima "¡Guau!", pero no quieres crear para ello un archivo aparte Dog.java.

Aquí es donde entran en juego las clases anónimas. Son clases sin nombre que se declaran y se crean justo en el lugar donde se usan. 🚀 Permiten heredar «sobre la marcha» de una clase sin crear un archivo aparte. En lugar de llenar el proyecto con muchos archivos pequeños de clases que se usan solo en un sitio, puedes escribir toda la lógica justo donde la necesitas.

¿Cómo es la sintaxis?

La sintaxis de las clases anónimas puede parecer inusual, pero en realidad es bastante sencilla:

VariableType name = new TypeToInherit() {
    // Aquí escribimos el cuerpo de la clase anónima
    // Sobrescribimos los métodos de la clase padre
};

Desgranemos esta sintaxis:

  • VariableType name: Es una declaración normal de una variable donde guardaremos nuestro nuevo objeto.
  • new TypeToInherit(): Aquí parece que estemos creando un nuevo objeto. Pero en lugar de un nombre de clase usamos el de la clase de la que queremos heredar. Fíjate en que después de los paréntesis () no hay punto y coma !
  • { ... }: Aquí abrimos llaves y escribimos toda la lógica de nuestra clase anónima. Podemos sobrescribir métodos de la clase padre o añadir nuestra propia lógica.

Ejemplo de herencia de una clase normal:

Volvamos a nuestro ejemplo del animal.

class Animal {
    void say() {
        System.out.println("El animal emite un sonido");
    }
}

// Creamos una clase anónima heredando de Animal
Animal dog = new Animal() {
    // Sobrescribimos el método say()
    @Override
    void say() {
        System.out.println("¡Guau, guau! 🐶");
    }
};

Animal cat = new Animal() {
    @Override
    void say() {
        System.out.println("¡Miau, miau! 🐱");
    }
};

dog.say(); // Imprimirá: ¡Guau, guau! 🐶
cat.say(); // Imprimirá: ¡Miau, miau! 🐱

En este ejemplo creamos dos objetos, dog y cat, que en esencia son clases anónimas que heredan de Animal. Y no hemos creado ningún archivo aparte.

Comparación de enfoques

// Forma habitual (creamos una clase aparte)
class Dog extends Animal {
@Override
void say() { System.out.println("¡Guau!"); }
}
Animal dog = new Dog();

// VS

// Clase anónima (todo en un solo lugar)
Animal dog = new Animal() {
@Override
void say() { System.out.println("¡Guau!"); }
};

El resultado es el mismo, pero la clase anónima es más corta y no ensucia el proyecto.

2. Nombre de la clase anónima tras la compilación

Las clases anónimas no tienen nombre en el código fuente, pero el compilador de Java, por supuesto, debe nombrarlas de algún modo para crear el archivo .class. Lo hace siguiendo una regla bien definida:

  • El nombre del archivo de una clase anónima está formado por el nombre de la clase externa en la que se declaró.
  • Tras el nombre de la clase externa se añade el signo de dólar $.
  • A continuación va el número de orden de la clase anónima en ese archivo, empezando por 1.

Así, si nuestro ejemplo con los animales está en el archivo Main.java, tras la compilación se crearán tres archivos:

  • Main.class
  • Main$1.class (nuestra clase anónima para el perro)
  • Main$2.class (nuestra clase anónima para el gato)

Si la clase anónima se declara dentro de un método que a su vez está en una clase interna, el nombre será más complejo, por ejemplo, OuterClass$InnerClass$1.class.

Es un convenio interno del compilador útil de conocer, pero que rara vez tiene importancia en el día a día. Lo principal es recordar que una clase anónima sigue siendo una clase completa, aunque no tenga nombre en el código fuente.

3. Aspectos importantes y limitaciones

Las clases anónimas son una herramienta potente, pero tienen sus reglas.

Acceso a variables. Una clase anónima puede usar variables del método que la rodea. Sin embargo, esas variables deben ser final o effectively final (es decir, su valor no cambia después de la inicialización).

public void doSomething() {
    String greeting = "¡Hola!"; // Esta variable es effectively final

    class OuterClass {
        void greet() {
            // Creamos una clase anónima dentro del método
            new Object() {
                void sayHello() {
                    System.out.println(greeting); // Esto está permitido
                    // greeting = "¡Adiós!"; // ¡Esto provocará un error!
                }
            }.sayHello();
        }
    }

    new OuterClass().greet();
}

¿Por qué? Porque la clase anónima puede «vivir» más que el propio método y, si pudiera cambiar la variable, eso causaría problemas.

Sin constructor. Como la clase anónima no tiene nombre, tampoco puede tener constructor. Pero puedes usar un bloque de inicialización para ejecutar código al crear el objeto:

Animal dog = new Animal() {
    // Bloque de inicialización
    {
        System.out.println("Inicialización de la clase anónima 🐶");
    }
    @Override
    void say() {
        System.out.println("¡Guau, guau!");
    }
};

Restricciones. Las clases anónimas no pueden declarar campos estáticos (excepto constantes) ni métodos estáticos. Siempre se crean como parte de otro objeto, por lo que no pueden ser static, public, protected ni private.

4. Detalles útiles

Cuándo usar clases anónimas

  • Necesitas heredar de una clase (o implementar una interfaz) solo una vez.
  • La implementación es pequeña: 1–2 métodos, no más de un par de decenas de líneas.
  • La clase se necesita solo en un lugar y no tiene sentido darle nombre.
  • Quieres evitar «ensuciar» el paquete con montones de clases pequeñas de un solo uso.

Escenarios típicos:

  • Manejadores de eventos (GUI, Swing, Android, etc.).
  • Paso de callbacks a métodos.
  • Implementación rápida de comparadores para ordenar colecciones.
  • Objetos modificados temporalmente (por ejemplo, para pruebas).

5. Interacción con la clase externa

Si una clase anónima se declara dentro de un método no estático o de un bloque de la clase externa, puede acceder a los campos y métodos de esa clase externa (¡incluso a los privados!).

public class Outer {
    private String secret = "Texto secreto";

    // Clase base
    class Printer {
        public void print() {
            System.out.println("Salida normal");
        }
    }

    public void revealSecret() {
        Printer p = new Printer() {
            @Override
            public void print() {
                System.out.println("Acceso a lo privado: " + secret);
            }
        };
        p.print();
    }

    public static void main(String[] args) {
        new Outer().revealSecret();
    }
}

6. Errores típicos al trabajar con clases anónimas

Error n.º 1: intentar modificar una variable del método envolvente.
Si declaras una variable fuera de la clase anónima e intentas modificarla después de usarla dentro de la clase anónima, el compilador dará error. La variable debe ser final o effectively final (no cambiar después de la inicialización).

Error n.º 2: clase anónima demasiado grande.
Si la clase anónima ha crecido hasta decenas de líneas y contiene varios métodos, es una señal de que conviene extraerla a una clase con nombre. De lo contrario, el código se volverá ilegible.

Error n.º 3: intentar usar métodos o campos estáticos.
En una clase anónima no se pueden declarar métodos ni campos estáticos (excepto constantes). Si realmente lo necesitas, es motivo para crear una clase interna normal.

Error n.º 4: olvidar el ámbito de visibilidad.
Una clase anónima solo es visible en el lugar donde se declara y no tiene nombre. Si necesitas reutilizarla varias veces, declara una clase normal.

1
Tarea
JAVA 25 SELF, nivel 16, lección 2
Bloqueada
La granja mágica: sonido único de la criatura 🪄
La granja mágica: sonido único de la criatura 🪄
1
Tarea
JAVA 25 SELF, nivel 16, lección 2
Bloqueada
Traductor intergaláctico: saludo instantáneo 🚀
Traductor intergaláctico: saludo instantáneo 🚀
1
Tarea
JAVA 25 SELF, nivel 16, lección 2
Bloqueada
Línea de producción: anuncio de inicio de operación 🏭
Línea de producción: anuncio de inicio de operación 🏭
1
Tarea
JAVA 25 SELF, nivel 16, lección 2
Bloqueada
Laboratorio secreto: revelando un mensaje cifrado 🕵️
Laboratorio secreto: revelando un mensaje cifrado 🕵️
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION