fbpx

Clases anónimas en JAVA

Las clases anónimas son clases internas sin nombre. Como no tienen nombre, no podemos usarlos para crear instancias de clases anónimas. Como resultado, tenemos que declarar e instanciar clases anónimas en una sola expresión.

Vídeo explicativo

Crear una clase anónima

Hay dos formas de crear una clase anónima, podemos extender una clase existente o implementar una interfaz.

Extender una clase

Cuando instanciamos una clase anónima a partir de una existente, usamos la siguiente sintaxis:

new ClaseAnonima(){}

Entre paréntesis, especificamos los parámetros que requiere el constructor de la clase que estamos extendiendo:

new Usuario("Juan") {
    @Override
    public String metodoDeClaseAnonima() {
        return "Esto es una clase anonima";
    }
}

Naturalmente, si el constructor de la clase principal no acepta argumentos, deberíamos dejar los paréntesis vacíos.

Implementar una interfaz

También podemos instanciar una clase anónima desde una interfaz:

new InterfazAnonima(){}

Obviamente, las interfaces de Java no tienen constructores, por lo que los paréntesis siempre quedan vacíos. Esta es la única forma en que debemos hacerlo para implementar los métodos de la interfaz:

new Runnable() {
    @Override
    public void run() {
        ...
    }
}

Instanciando una clase anónima

Una vez que hemos instanciado una clase anónima, podemos asignar esa instancia a una variable para poder hacer referencia a ella en algún lugar más adelante.

Podemos hacer esto usando la sintaxis estándar para expresiones Java:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        ...
    }
};

Como ya mencionamos, una declaración de clase anónima es una expresión, por lo tanto, debe ser parte de una declaración. Esto explica por qué hemos puesto un punto y coma al final de la instrucción.

Obviamente, podemos evitar asignar la instancia a una variable si creamos esa instancia en línea:

List<Runnable> runnables = new ArrayList<Runnable>();
runnables.add(new Runnable() {
    @Override
    public void run() {
        ...
    }
});

Deberíamos usar esta sintaxis con mucho cuidado, ya que podría afectar fácilmente la legibilidad del código, especialmente cuando la implementación del método run() ocupa mucho espacio.

Propiedades de clase anónima

Hay ciertas particularidades en el uso de clases anónimas con respecto a las clases habituales de nivel superior. Aquí tocamos brevemente las cuestiones más prácticas. Para obtener la información más precisa y actualizada, siempre podemos consultar la the Java Language Specification.

Constructor

La sintaxis de las clases anónimas no nos permite hacerlas implementar múltiples interfaces. Durante la construcción, puede existir exactamente una instancia de una clase anónima. Por lo tanto, nunca pueden ser abstractos. Como no tienen nombre, no podemos extenderlos. Por la misma razón, las clases anónimas no pueden tener constructores declarados explícitamente.

De hecho, la ausencia de un constructor no representa ningún problema para nosotros por las siguientes razones:

  • Creamos instancias de clase anónimas en el mismo momento en que las declaramos
  • Desde instancias de clases anónimas, podemos acceder a variables locales y miembros de la clase adjunta

Miembros estáticos

Las clases anónimas no pueden tener miembros estáticos excepto aquellos que son constantes.

Por ejemplo, esto no compilará:

new Runnable() {
    static final int x = 0;
    static int y = 0; // error de compilación

    @Override
    public void run() {...}
};

Alcance de las variables

Las clases anónimas capturan variables locales que están en el alcance del bloque en el que hemos declarado la clase:

int contador = 1;
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Runnable con variables desde fuera: " + contador);
    }           
};

Como vemos, las variables locales “contador” y “runnable” están definidas en el mismo bloque. Por esta razón, podemos acceder al recuento desde dentro de la declaración de la clase.

Tenga en cuenta que para poder usar variables locales, deben ser efectivamente finales. Desde JDK 8, ya no se requiere que declaremos variables con la palabra clave final. Sin embargo, esas variables deben ser definitivas. De lo contrario, obtenemos un error de compilación:

[ERROR] local variables referenced from an inner class must be final or effectively final

Para que el compilador decida que una variable es, de hecho, inmutable, en el código, debe haber un solo lugar en el que le asignemos un valor.

Solo mencionemos que, como toda clase interna, una clase anónima puede acceder a todos los miembros de su clase envolvente.