Overview
In Java ist die Mehrfachvererbung nicht erlaubt. Doch aus dieser scheinbaren Schwäche gewinnt unsere Lieblingsprogrammiersprache eine ihrer größten Stärken. Mit Interfaces nämlich umschiffen wir die Regel der Einfachvererbung elegant und erkunden neue Möglichkeiten, hoch flexiblen Code zu schreiben.
Wissen Sie, was ein Cyborg ist? Laut Wikipedia bezeichnet der Begriff Mischwesen aus lebendigem Organismus und Maschine.
Übertragen wir die Beziehung zwischen Mensch, Maschine und Cyborg in die Objektorientierung, könnte sich folgende Klassenhierarchie ergeben:
Die Klasse Cyborg braucht Eigenschaften und Methoden von Mensch und von Maschine und würde daher gleichzeitig von Mensch und Maschine erben. Doch da gibt es ein Problem:
Könnte Java (wie etwa C++) Mehrfachvererbung, würde das unsere Programme unnötig verkomplizieren: Stellen Sie sich einfach mal vor, dass sowohl Mensch als auch Maschine eine Methode namens laufen() haben. Wenn nun Cyborg von beiden Klassen die Methode erben würde, hätten wir ein fettes Dilemma, da es völlig unklar wäre, welche laufen()-Methode auf einem Cyborg-Objekt ausgeführt werden sollte.
Da eine Java-Klasse also nur von maximal einer anderen Klasse erben kann, bleibt die Frage weiter offen, wie wir unseren Cyborg hinbekommen.
Mit Interfaces (Schnittstellen) lösen wir in Java das Problem der Einfachvererbung und ermöglichen, dass eine Klasse auf mehrere Typen zurückgeht. Eine Klasse kann neben der Oberklasse auf eine beliebige Anzahl an Interfaces zurückgehen - wir sagen dann, dass eine Klasse ein Interface implementiert.
Die Klasse Cyborg erweitert die Klasse Mensch und implementiert das Interface Maschine.
Eine Oberklasse zu erweitern und ein Interface zu implementieren sind zwei unterschiedliche Vorgänge. Dies kommt auch in unterschiedlichen Schlüsselwörtern (extends und implements) zum Ausdruck:
public class Cyborg extends Mensch implements Maschine{
//
}
Wenn eine Klasse sowohl erbt als auch ein Interface implementiert, muss extends immer vor implements stehen.
Mehrere implementierte Interfaces werden im Klassenkopf kommasepariert geschrieben.
Interfaces sind keine Klassen, ähneln diesen aber im Aufbau. Der folgende Code zeigt den Interface-Typ Maschine:
interface Maschine {
void ladeBatterie();
void toolsTesten();
boolean funktionsfaehig();
}
Anhand von Maschine können wir die verpflichtenden Eigenschaften eines Interface schon erkennen:
Wir müssen uns merken: Der fehlende Access-Modifier meint nicht, dass die Methoden default-Zugriff hätten, sondern dass sie "automatisch" public sind.
Ein Interface ist wie eine 100%-ige abstrakte Klasse. Wenn eine Klasse nicht alle Methoden der Interfaces implementiert (d.h. Methodenkörper liefert), so erbt sie damit abstrakte Methoden. Die Klasse muss dann wiederum selbst als abstract gekennzeichnet werden.
In unserem Fall heißt das: Entweder die Klasse Cyborg macht durch Implementierung alle drei Methoden ladeBatterie(), toolsTesten() und funktionsfaehig() konkret oder sie muss selbst als abstrakt deklariert werden.
Da von Interfaces keine Instanzen (Objekte) erzeugt werden können, gibt es auch keine Instanzvariablen.
Konstanten allerdings sind kein Problem. Zum Beispiel:
public static final double maxEnergie = 100.0;
Da in Interfaces ausschließlich öffentliche Konstanten-Variablen erlaubt sind, müssen die Schlüsselwörter public, static und final nicht explizit genannt werden (auch wenn es natürlich trotzdem möglich ist). Der Compiler ergänzt die fehlenden Angaben für uns.
Ergänzen wir unser Interface Maschine nun um die Konstante maxEnergie:
interface Maschine {
double maxEnergie = 100.0; // = public static final
void ladeBatterie();
void toolsTesten();
boolean funktionsfaehig();
}
Interfaces sind super, um in Java doch noch eine Art Mehrfachvererbung hinzubekommen. Aber Sie haben noch einen zweiten großen Vorteil.
Wenn unsere Klassen ein Interface implementieren, spielen sie eine "Rolle" und es ist dabei völlig schnuppe, aus welchem Vererbungsbaum sie kommen:
Cyborg und Cyberdog haben keine gemeinsame Vererbungsstruktur. Da sie aber das Interface Maschine implementieren, können sie beide die Rolle Maschine spielen: Sowohl der Cyborg (Mensch) als auch der Cyberdog (Hund) sind Maschinen.
Diese Tatsache hat einen riesigen Nutzen: Da ein Interface - genau wie eine Klasse - einen Typ definiert, können wir Referenzvariablen oder Sammlungen von einem Interface-Typ deklarieren. Damit können wir die Prinzipien der Polymorphie nach allen Regeln der Kunst voll ausreizen und unseren Code unwiderstehlich machen.
Hier ein Beispiel:
ArrayList<Maschine> maschinen = new ArrayList<>();
maschinen.add(new Cyborg());
maschinen.add(new Cyberdog());
maschinen.add(new Waschmaschine());
Wir erstellen eine ArrayList, die alle Typen aufnehmen kann, die das Interface Maschine implementieren. Anschließend packen wir drei passende neue anonyme Objekte rein.
Cyborg, Cyberdog und jetzt sogar Waschmaschine entstammen ganz unterschiedlichen Vererbungsstrukturen. Aber sie haben alle neben ihres vererbten Typs zusätzlich den Interface-Typ Maschine. Mit anderen Worten: Es sind Maschinen; und das ist ihre Gemeinsamkeit.
Java Basics
[Java einrichten] [Variablen] [Primitive Datentypen] [Operatoren] [if else] [switch-case] [Arrays] [Schleifen]
Objektorientierung
[Einstieg] [Variablen ] [Konstruktor] [Methoden] [Rekursion] [Statische Member] [Initializer] [Pass-by-value] [Objektsammlungen] [Objektinteraktion] [Objekte löschen]
Klassenbibliothek
[Allgemeines] [String ] [Math] [Wrapper] [Scanner] [java.util.Arrays] [Date-Time-API]
Vererbung
[Einstieg Vererbung] [Konstruktoren bei Vererbung ] [Der protected Zugriffsmodifikator] [Abstrakte Klassen und Methoden] [Polymorphie in Java] [Typumwandlung] [Die Klasse Object] [Die toString()-Methode] [Objekte vergleichen] [Was ist ein Interface?]