Java Vererbung erklärt sich am besten an einer Tierhierarchie: Eine Unterklasse baut mit extends auf einer Oberklasse auf, erhält deren Felder und Methoden automatisch und darf geerbte Methoden mit derselben Signatur überschreiben.
Ein Kurs soll Klassen für Hund und Katze schreiben. Die erste Fassung kopiert dieselben Felder und Methoden in beide Klassen, sodass jede Änderung doppelt erfolgen muss. Die Lösung besteht darin, die gemeinsamen Teile in eine Klasse Tier zu legen und Hund sowie Katze davon abzuleiten. Eine Einordnung im Gesamtzusammenhang des Fachs bietet die Übersicht java lernen schule, die Grundlagen zu Klassen und Objekten stehen unter objektorientierte programmierung java schule.
Vererbung als ist-ein-Beziehung
Vererbung erlaubt es einer neuen Klasse, auf einer bestehenden aufzubauen. Die Oberklasse enthält, was alle Tiere gemeinsam brauchen, etwa das Feld name und die Methode lautGeben. Die Unterklassen Hund und Katze erhalten diese Felder und Methoden automatisch und ergänzen nur, was sie von anderen Tieren unterscheidet. Coddy beschreibt das als Wiederverwendung nach dem ist-ein-Prinzip, und genau an diesem Prinzip entscheidet sich, ob Vererbung passt.
Der Test dafür ist ein Satz. „Ein Hund ist ein Tier“ stimmt, also passt eine Unterklasse Hund zur Oberklasse Tier. „Ein Hund ist ein Halsband“ stimmt dagegen nicht. Ein Halsband gehört als eigenes Objekt in ein Feld des Hundes, und der Hund nutzt dessen Funktionen, ohne von ihm abgeleitet zu sein. Der Satz entscheidet also über die Form der Klassenbeziehung, nicht über die Länge des Codes.

Typische Irrtümer im Vergleich
Beim ersten Kontakt mit Vererbung kehren dieselben Fehlannahmen wieder. Die Tabelle stellt drei davon der Regel gegenüber, die in den Quellen steht.
| Annahme | Was in Java gilt | Folge für den Code |
|---|---|---|
| Die Unterklasse erbt einfach alles. | Was im Elternteil public oder protected ist, steht im Kind zur Verfügung. | Mitglieder, die Unterklassen brauchen, als protected oder public deklarieren; reine private Mitglieder gehören nicht zu dieser Liste. |
| Der Aufruf von super ist Geschmackssache. | super(…) muss die erste Anweisung im Konstruktor der Unterklasse sein. | Der Konstruktor der Unterklasse beginnt mit dem super-Aufruf, bevor eigene Anweisungen stehen. |
| Ohne @Override funktioniert Überschreiben nicht. | Die Annotation ist nicht erforderlich, lässt den Compiler aber prüfen. | Überschreiben gelingt auch ohne Annotation; @Override sorgt dafür, dass der Compiler die Überschreibung prüft. |
Die Angaben stammen aus der Einführung zur Vererbung bei Coddy und aus dem Java-Wegweiser der DH Cologne. Die drei Fehler betreffen genau die Stellen, an denen Unterklasse und Oberklasse zusammentreffen: den Zugriff auf geerbte Mitglieder, den Konstruktor und die Überschreibung. Wer diese Stellen kennt, prüft sie beim Schreiben zuerst.
Unterklasse mit extends und super schreiben
Die Klassenkopfzeile
Eine Unterklasse wird mit dem Schlüsselwort extends geschrieben. Hinter dem Namen der neuen Klasse folgt extends und der Name der Oberklasse. Mehr steht in der Kopfzeile nicht; neue Felder oder Methoden gehören wie gewohnt in den Klassenrumpf. Das folgende Beispiel zeigt eine Oberklasse und eine Unterklasse, die den Namen an den Konstruktor der Oberklasse weitergibt.

public class Tier {
protected String name;
public Tier(String name) { this.name = name; }
public String lautGeben() { return “…”; }
}
public class Hund extends Tier {
public Hund(String name) { super(name); }
}
Der Hund besitzt damit das Feld name und die Methode lautGeben, obwohl beide nicht im Quelltext der Klasse Hund stehen. Die Klasse Hund enthält nur den Konstruktor, der den Namen an die Oberklasse übergibt. Ob das Feld name als protected deklariert wird, ist eine Entwurfsentscheidung: Damit legt die Oberklasse fest, wie viel sie nach unten offenlegt.
Der Konstruktor und super
Die Unterklasse ruft den Konstruktor der Oberklasse mit super auf, im Beispiel mit dem Namen als Argument. Der Java-Wegweiser nennt es üblich und sinnvoll, in Konstruktoren zuerst den Konstruktor der jeweiligen Superklasse aufzurufen. Die Regel, dass der Aufruf die erste Anweisung sein muss, steht in der Tabelle oben. Eine Unterklasse entsteht in drei Schritten:

- Kopfzeile schreiben. Den Klassennamen mit extends und dem Namen der Oberklasse verbinden.
- Konstruktor anbinden. Als erste Anweisung den passenden Konstruktor mit super(…) aufrufen.
- Erweitern. Neue Felder ergänzen und nur die Methoden im Rumpf verändern, deren Verhalten sich tatsächlich ändern soll.
Methoden überschreiben
Überschreiben heißt, dass eine Unterklasse eine geerbte Methode mit derselben Signatur neu definiert. Laut DH Cologne können die Methoden von Klassen in Subklassen überschrieben werden. Danach referenziert ein Aufruf die überschreibende Methode der erweiternden Klasse. Der Unterschied ist daher praktisch spürbar: Derselbe Aufruf liefert je nach Klasse des Objekts ein anderes Ergebnis.
public class Hund extends Tier {
public Hund(String name) { super(name); }
@Override
public String lautGeben() { return “Wau”; }
}
Überschreiben und Überladen unterscheiden
Beide Begriffe klingen ähnlich, beschreiben aber verschiedene Vorgänge. Beim Überschreiben bleibt die Signatur gleich, und die Unterklasse ersetzt das Verhalten der geerbten Methode. Beim Überladen trägt eine Methode denselben Namen, hat aber eine andere Parameterliste, sodass mehrere Varianten nebeneinander bestehen. Wer in der Unterklasse einen anderen Parametertyp schreibt, überlädt also nur, statt zu überschreiben. Genau diese Verwechslung fängt @Override ab, weil die Annotation den Compiler die Überschreibung prüfen lässt.
Polymorphie an der Tierhierarchie
Die Grundlage der Polymorphie steht im Java-Wegweiser der DH Cologne: Jede Instanz einer Klasse ist auch eine Instanz aller Superklassen. Ein Hund ist damit zugleich ein Tier. Eine Variable vom Typ Tier darf also ein Hundeobjekt speichern. Ruft man dort eine überschriebene Methode auf, führt Java die Version der Klasse aus, zu der das Objekt tatsächlich gehört. Der praktische Gewinn liegt darin, dass der aufrufende Code nicht wissen muss, welche Tierart vorliegt.
Tier t = new Hund(“Rex”);
System.out.println(t.lautGeben());
Tier[] tiere = { new Hund(“Rex”), new Katze(“Mia”) };
for (Tier tier : tiere) {
System.out.println(tier.lautGeben());
}
Die Klasse Katze wird wie Hund mit extends Tier geschrieben und überschreibt lautGeben mit einem eigenen Rückgabewert, etwa „Miau“. Die Schleife kennt nur den Typ Tier. Sofern beide Klassen lautGeben überschreiben, erscheinen auf der Konsole „Wau“ und „Miau“, obwohl die Schleife zwischen Hund und Katze nicht unterscheidet. Neue Unterklassen lassen sich ergänzen, ohne die Schleife zu ändern, solange sie von Tier erben und lautGeben überschreiben. Wie Arrays solche Sammlungen aufnehmen, zeigt java arrays erklärt.
Wann Vererbung die falsche Wahl ist
Vererbung passt nur, wenn der ist-ein-Satz ohne Verrenkung stimmt. Drei Situationen sprechen eher gegen sie.
- Die Klasse braucht nur einzelne Funktionen. Dann passt ein Objekt als Feld meist besser, weil die Beziehung nicht ist-ein lautet.
- Der Satz stimmt nur mit Umschreibung. Lässt sich ist-ein nur durch lange Formulierungen retten, ist die Beziehung wahrscheinlich anders zu modellieren.
- Zwei Oberklassen wären nötig. Jede Klasse kann laut DH Cologne in Java nur von einer anderen Klasse erben. Wer die einzige Oberklasse für ein Merkmal verbraucht, kann sie für eine andere Hierarchie nicht mehr nutzen.
Im Zweifel gilt diese Reihenfolge: erst den ist-ein-Satz prüfen, dann die Klassen schreiben. Eine kurze Skizze der Beziehung ist der günstigere Ort für diese Entscheidung, weil sich Pfeile auf Papier leichter umzeichnen lassen als fertige Klassen.
Frequently asked questions
| Frage | Antwort |
|---|---|
| Wie lässt sich verhindern, dass eine Klasse erweitert wird? | Mit dem Schlüsselwort final bei der Klasse. Laut DH Cologne verhindert das das Erweitern. |
| Wer darf auf protected-Mitglieder zugreifen? | Der Zugriffsmodifizierer protected erlaubt laut DH Cologne nur den Zugriff durch erbende Klassen. |
| Was passiert, wenn die Oberklasse keinen Konstruktor ohne Argumente hat? | Hat der Elternteil keinen solchen Konstruktor, lässt sich der Code laut Coddy nicht kompilieren, solange die Unterklasse nicht per super einen passenden Konstruktor aufruft. |



