Anonyme Klassen

Anonyme Klassen (oder auch anonyme innere Klassen) bieten eine kompakte Schreibweise, wenn man für die Implementierung eines Interfaces oder einer abstrakten Klasse keine eigene Klasse erstellen möchte. In Java 8 können Lambda Ausdrücke als anonyme Klassen von funktionalen Interfaces gesehen werden.

Inhaltsverzeichnis

Anonyme Klasse als Implementierung eines Interfaces

Um ein Interface zu implementieren oder von einer Klasse zu erben erstellt man normalerweise eine neue Klasse die man dann instanziieren kann:

public class MyTask implements Runnable{

    @Override
    public void run() {
        System.out.println("I run!");
    }
} 

new Thread(new MyTask()).start();

Im Beispiel wird die Klasse MyTask erstellt, die das Interface Runnable implementiert. Das heißt die Klasse muss die Methode run() implementieren. Dem Thread wird eine neue Instanz der Klasse übergeben.

Das Interface wie oben zu implementieren ist grundsätzlich kein schlechter Weg, jedoch muss für jeden Task eine eigene Klasse erstellt werden. Das ist manchmal viel Aufwand, gerade wenn der Task sehr klein ist und nur an einer Stelle verwendet wird.

Wenn man nun nicht für jeden minimalen Task eine eigene Klasse erstellen will, kann man statt dem Runnable Objekt auch eine innere Klasse übergeben.

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("I run!");
    }
}).start();

Syntax einer anonymen Klasse

Eine anonyme Klasse besteht aus einem Konstruktor-Aufruf und einem Code-Block, also im minimalen Fall

new Object(){};

Der Code-Block {} kann nun beliebigen Code, wie Variablen und Methoden enthalten.

Die anonyme Klasse muss auf jeden Fall Implementierungen der abstakten Methoden des Interfaces oder der Super-Klasse bereitstellen (z.B. run() Methode im Beispiel oben). Optional können auch nicht-abstrakte Methoden überschrieben werden.

Das folgende Beispiel soll nicht als Best-Practice missverstanden werden, sondern als Beispiel, was alles möglich ist:

final List<String> names = Arrays.asList("Thomas", "Anja", "Heinz");
List<String> loggingList = new ArrayList<String>(names) {

    private void log(String s){
        System.out.println(this.toString() + " + " + s);
    }

    @Override
    public boolean add(String s) {
        log(s);
        return super.add(s);
    }
};
loggingList.add("Maria");
loggingList.add("Susi");

// Ausgabe
// [Thomas, Anja, Heinz] + Maria
// [Thomas, Anja, Heinz, Maria] + Susi

Das obige Beispiel zeigt, dass für die anonyme Klasse nicht unbedingt der No-Arg-Konstruktor verwendet werden muss. Im Beispiel weider der Konstruktor ArrayList(Collection<? extends E> c) verwendet und die Instanz der anonymen Klasse gleich mit Daten bestückt.

Die anonyme Klasse überschreibt die Methode add(), und definiert eine eigene private Methode log(), die alle Elemente plus das neue Element ausgibt.

Lambda Expressions statt anonymen Klassen

Wenn das Interface der anonymen Klasse ein funktionales Interface ist, also nur eine abstakte Methode enthält, kann statt der anonymen Klasse auch eine Lambda Expression verwendet werden.

Aus der anonymen Klasse

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("I run!");
    }
}).start();

wird der Lambda Ausdruck

new Thread(()-> System.out.println("I run!")).start();

Zu beachten ist, dass ein Lambda Ausdruck keine anonyme Klasse ist. Auch wenn die meisten anonymen Klassen wohl durch Lambdas ersetzt werden können, ist ein Lambda-Ausdruck immer stateless, anonyme Klassen können durchaus einen Status enthalten (siehe Beispiel mit der ArrayList oben!).


Ähnliche Artikel