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 werdendefault-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)); // 7java.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