Vererbung
Vererbung in Java verstehen: extends, super, Methoden überschreiben und die Vererbungshierarchie. Mit praktischen Beispielen.
Vererbung in Java
Vererbung ist eines der vier Grundprinzipien der objektorientierten Programmierung. Sie ermoeglicht dir, eine neue Klasse auf Basis einer bestehenden zu erstellen — und dabei Code wiederzuverwenden, statt alles neu zu schreiben.
Was ist Vererbung?
Stell dir vor, du hast eine Klasse Tier mit allgemeinen Eigenschaften. Hund und Katze teilen diese Eigenschaften, haben aber zusaetzlich eigene:
Tier
(name, alter, fressen())
/ \
Hund Katze
(bellen()) (miauen())
Die Unterklassen erben alles von der Oberklasse und koennen es erweitern oder ueberschreiben.
extends — Vererbung in Java
// Oberklasse (Superklasse / Elternklasse)
public class Tier {
String name;
int alter;
Tier(String name, int alter) {
this.name = name;
this.alter = alter;
}
void fressen() {
System.out.println(name + " frisst.");
}
void vorstellen() {
System.out.printf("%s ist %d Jahre alt.%n", name, alter);
}
}
// Unterklasse (Subklasse / Kindklasse)
public class Hund extends Tier {
String rasse;
Hund(String name, int alter, String rasse) {
super(name, alter); // Konstruktor der Oberklasse aufrufen
this.rasse = rasse;
}
void bellen() {
System.out.println(name + " sagt: Wuff!");
}
}
public class Katze extends Tier {
boolean istHauskatze;
Katze(String name, int alter, boolean istHauskatze) {
super(name, alter);
this.istHauskatze = istHauskatze;
}
void miauen() {
System.out.println(name + " sagt: Miau!");
}
}
var rex = new Hund("Rex", 5, "Schaeferhund");
rex.vorstellen(); // Geerbt von Tier
rex.fressen(); // Geerbt von Tier
rex.bellen(); // Eigene Methode
var mia = new Katze("Mia", 3, true);
mia.vorstellen(); // Geerbt von Tier
mia.miauen(); // Eigene Methode
super — Die Oberklasse ansprechen
super() im Konstruktor
super() ruft den Konstruktor der Oberklasse auf und muss die erste Anweisung sein:
public class Mitarbeiter {
String name;
double gehalt;
Mitarbeiter(String name, double gehalt) {
this.name = name;
this.gehalt = gehalt;
}
}
public class Manager extends Mitarbeiter {
int teamGroesse;
Manager(String name, double gehalt, int teamGroesse) {
super(name, gehalt); // MUSS erste Anweisung sein!
this.teamGroesse = teamGroesse;
}
}
super fuer Methoden
Mit super.methode() rufst du die Methode der Oberklasse auf:
public class Tier {
String name;
Tier(String name) {
this.name = name;
}
String beschreibung() {
return name + " ist ein Tier";
}
}
public class Hund extends Tier {
String rasse;
Hund(String name, String rasse) {
super(name);
this.rasse = rasse;
}
@Override
String beschreibung() {
return super.beschreibung() + " (Hund, Rasse: " + rasse + ")";
}
}
var rex = new Hund("Rex", "Schaeferhund");
System.out.println(rex.beschreibung());
// Rex ist ein Tier (Hund, Rasse: Schaeferhund)
Methoden ueberschreiben (Override)
Unterklassen koennen Methoden der Oberklasse ueberschreiben, um eigenes Verhalten zu definieren:
public class Form {
String name;
Form(String name) {
this.name = name;
}
double flaeche() {
return 0; // Standard: keine Flaeche
}
void info() {
System.out.printf("%s: Flaeche = %.2f%n", name, flaeche());
}
}
public class Kreis extends Form {
double radius;
Kreis(double radius) {
super("Kreis");
this.radius = radius;
}
@Override
double flaeche() {
return Math.PI * radius * radius;
}
}
public class Rechteck extends Form {
double breite;
double hoehe;
Rechteck(double breite, double hoehe) {
super("Rechteck");
this.breite = breite;
this.hoehe = hoehe;
}
@Override
double flaeche() {
return breite * hoehe;
}
}
var kreis = new Kreis(5);
kreis.info(); // Kreis: Flaeche = 78.54
var rechteck = new Rechteck(4, 6);
rechteck.info(); // Rechteck: Flaeche = 24.00
@Override-Annotation
Die @Override-Annotation ist freiwillig, aber dringend empfohlen. Sie sagt dem Compiler: “Ich ueberschreibe absichtlich eine Methode.” Wenn du dich vertippst, gibt es einen Fehler:
@Override
double flaeche() { ... } // OK: ueberschreibt Form.flaeche()
@Override
double flaech() { ... } // FEHLER! Keine Methode "flaech" in der Oberklasse
Vererbungshierarchie
Java unterstuetzt nur Einfachvererbung — eine Klasse kann nur von einer Klasse erben:
// OK: Einfachvererbung
class Tier { }
class Hund extends Tier { }
class Schaeferhund extends Hund { }
// FEHLER: Mehrfachvererbung gibt es in Java nicht
// class Hybrid extends Hund, Katze { } // Fehler!
Fuer “Mehrfachvererbung” verwendet Java Interfaces (kommt im naechsten Kapitel).
Die Klasse Object
Jede Klasse in Java erbt automatisch von Object — der Wurzel aller Klassen:
// Das hier:
public class MeineKlasse { }
// Ist das Gleiche wie:
public class MeineKlasse extends Object { }
Von Object geerbt:
toString()— String-Darstellungequals(Object o)— GleichheitsvergleichhashCode()— Hash-WertgetClass()— Klassen-Info
public class Student {
String name;
Student(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student: " + name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student s)) return false;
return name.equals(s.name);
}
}
var s1 = new Student("Max");
System.out.println(s1); // Student: Max
System.out.println(s1.equals(new Student("Max"))); // true
final — Vererbung verhindern
Finale Klassen
final class Konstanten {
static final double PI = 3.14159265;
// Diese Klasse kann nicht erweitert werden!
}
// class MeineKonstanten extends Konstanten { } // FEHLER!
Finale Methoden
public class Basis {
final void wichtigeMethode() {
// Diese Methode kann NICHT ueberschrieben werden
}
}
public class Abgeleitet extends Basis {
// @Override
// void wichtigeMethode() { } // FEHLER! Methode ist final
}
Sealed Classes (Java 17+)
Mit sealed kannst du genau festlegen, welche Klassen erben duerfen:
public sealed class Fahrzeug permits Auto, Motorrad, Fahrrad {
String name;
Fahrzeug(String name) { this.name = name; }
}
public final class Auto extends Fahrzeug {
Auto(String name) { super(name); }
}
public final class Motorrad extends Fahrzeug {
Motorrad(String name) { super(name); }
}
public final class Fahrrad extends Fahrzeug {
Fahrrad(String name) { super(name); }
}
// class Dreirad extends Fahrzeug { } // FEHLER! Nicht in permits-Liste
Wann Vererbung verwenden?
Die goldene Regel: “Ist-ein”-Beziehung
// GUT: Hund IST EIN Tier
class Hund extends Tier { }
// GUT: Manager IST EIN Mitarbeiter
class Manager extends Mitarbeiter { }
// SCHLECHT: Motor IST KEIN Auto (Motor ist TEIL eines Autos)
// class Motor extends Auto { } // Falsch!
// Besser: class Auto { Motor motor; } // Komposition!
Uebungen
Uebung 1: Fahrzeug-Hierarchie
Erstelle eine Oberklasse Fahrzeug mit Feldern marke und geschwindigkeit. Erstelle Unterklassen Auto (mit tueren) und Motorrad (mit helmPflicht).
Uebung 2: Formen
Erstelle eine Hierarchie: Form (Oberklasse) mit Kreis, Rechteck und Dreieck. Jede Form soll flaeche() und umfang() ueberschreiben.
Uebung 3: Mitarbeiter
Erstelle Mitarbeiter als Oberklasse und Manager und Entwickler als Unterklassen. Ueberschreibe die Methode gehaltBerechnen() je nach Rolle.
Uebung 4: toString und equals
Ueberschreibe toString() und equals() fuer eine Klasse Buch mit Titel und Autor.
Was kommt als Naechstes?
In der naechsten Lektion lernst du Interfaces und abstrakte Klassen — damit kannst du Vertraege definieren, die Klassen erfuellen muessen, und die Einschraenkung der Einfachvererbung umgehen.
Zusammenfassung
- Vererbung (
extends) ermoeglicht Code-Wiederverwendung und Hierarchien super()ruft den Konstruktor der Oberklasse auf (muss erste Anweisung sein)@Overridemarkiert ueberschriebene Methoden (immer verwenden!)- Java hat nur Einfachvererbung (eine Oberklasse)
- Alle Klassen erben von
Object(toString, equals, hashCode) finalverhindert Vererbung (Klasse) oder Ueberschreibung (Methode)- Sealed Classes begrenzen, welche Klassen erben duerfen
- Verwende Vererbung nur fuer “ist-ein”-Beziehungen
Pro-Tipp: Bevorzuge Komposition ueber Vererbung — das ist eines der wichtigsten Designprinzipien in Java. Statt class Auto extends Motor schreibe class Auto { Motor motor; }. Vererbung sollte nur fuer echte “ist-ein”-Beziehungen verwendet werden. In der Praxis ist Komposition flexibler und fuehrt zu besser wartbarem Code!