EMZETT.
Login

Interface

Kurz: Ein reiner Vertrag aus Methodensignaturen ohne eigene Implementierung (Ausnahmen: default-Methoden) — eine Klasse “verspricht” mit implements, alle vorgeschriebenen Methoden bereitzustellen.

Genauer: Anders als bei Inheritance (nur eine Oberklasse) kann eine Klasse in Java mehrere Interfaces gleichzeitig implementieren — das umgeht die Einschränkung der Einfachvererbung. Interfaces sind die Grundlage, um unterschiedliche Klassen über ein gemeinsames Verhalten austauschbar zu machen, ohne eine gemeinsame Vererbungshierarchie zu brauchen.

interface Fahrbar {
    void fahren();
}
class Auto implements Fahrbar {
    public void fahren() { System.out.println("Vroom"); }
}

Im Detail

interface Fahrbar {
    void fahren(); // implizit "public abstract"
 
    default void hupen() { // seit Java 8: Standardimplementierung möglich
        System.out.println("Hup!");
    }
 
    static int maxGeschwindigkeit() { // statische Interface-Methode
        return 250;
    }
}
 
interface Schwimmfaehig {
    void schwimmen();
}
 
// Eine Klasse kann MEHRERE Interfaces gleichzeitig implementieren
class Amphibienfahrzeug implements Fahrbar, Schwimmfaehig {
    public void fahren() { System.out.println("Fährt auf der Straße"); }
    public void schwimmen() { System.out.println("Schwimmt im Wasser"); }
}
 
Fahrbar f = new Amphibienfahrzeug();
f.fahren();
f.hupen(); // nutzt die Default-Implementierung, muss nicht überschrieben werden

default-Methoden wurden mit Java 8 eingeführt, um ein konkretes Problem zu lösen: Interfaces nachträglich um neue Methoden zu erweitern, ohne ALLE bestehenden implementierenden Klassen im gesamten Ökosystem zu brechen (das berühmteste Beispiel ist forEach() auf Collection, das erst nachträglich als default-Methode ergänzt wurde). Statische Methoden auf Interfaces bündeln Hilfsfunktionen, die logisch zum Interface gehören, aber keine konkrete Implementierung brauchen. Wichtig bleibt der Kernunterschied zur abstrakten Klasse: ein Interface kann (bis auf statische/final-Konstanten) keinen eigenen veränderlichen Zustand (Instanzfelder) halten — das bleibt Klassen vorbehalten.

Funktionale Interfaces

Ein Interface mit GENAU einer abstrakten Methode heißt “funktionales Interface” und ist die Grundlage für Lambda-Ausdrücke — die @FunctionalInterface-Annotation lässt den Compiler prüfen, dass diese Bedingung eingehalten wird:

@FunctionalInterface
interface Rechenoperation {
    int berechne(int a, int b);
}
 
Rechenoperation addition = (a, b) -> a + b; // Lambda statt einer vollständigen Klasse
System.out.println(addition.berechne(3, 4)); // 7

java.util.function liefert bereits fertige, vielfach wiederverwendbare funktionale Interfaces wie Function<T, R>, Predicate<T> und Consumer<T>, sodass für gängige Fälle gar kein eigenes Interface mehr definiert werden muss.

Konflikte bei mehreren Default-Methoden

Implementiert eine Klasse zwei Interfaces, die beide eine default-Methode mit demselben Namen mitbringen, entsteht ein Konflikt, den der Compiler NICHT automatisch auflöst — die implementierende Klasse muss die Methode explizit selbst überschreiben:

interface A { default void gruss() { System.out.println("Hallo von A"); } }
interface B { default void gruss() { System.out.println("Hallo von B"); } }
 
class C implements A, B {
    public void gruss() { // MUSS überschrieben werden, sonst Compiler-Fehler
        A.super.gruss(); // kann gezielt eine bestimmte Interface-Version aufrufen
    }
}

Das ist Javas bewusst gewählter Kompromiss, um das Diamond Problem bei Default-Methoden zu vermeiden, ohne Mehrfachvererbung von Interfaces ganz zu verbieten.

Siehe auch: Abstraction, Inheritance, Polymorphism, Lambda