Vererbung
Eine Lehrerin ist eine Person. Ein Schüler ist eine Person. Beide haben einen Namen und ein Geburtsjahr – und darüber hinaus jeweils etwas Eigenes.
Man könnte beide Klassen unabhängig voneinander schreiben. Dann stünde der gemeinsame Teil zweimal da – und du weißt inzwischen, warum das eine schlechte Idee ist.
Die Oberklasse
classDiagram
class Person {
#String name
#int geburtsjahr
+Person(String pName, int pGeburtsjahr)
+String getName()
+int alterImJahr(int pJahr)
+String beschreibung()
}
class Lehrer {
-String fach
+Lehrer(String pName, int pGeburtsjahr, String pFach)
+String beschreibung()
}
class Schueler {
-int jahrgangsstufe
+Schueler(String pName, int pGeburtsjahr, int pStufe)
+String beschreibung()
}
Person <|-- Lehrer
Person <|-- Schueler
Der Pfeil mit dem leeren Dreieck zeigt von der Unterklasse zur Oberklasse und bedeutet „ist ein“: Ein Lehrer ist eine Person.
| Schreibweise | Bedeutung |
|---|---|
class Lehrer extends Person |
Lehrer erbt von Person und bekommt alle Attribute und Methoden |
super(pName, pGeburtsjahr) |
ruft den Konstruktor der Oberklasse auf – muss die erste Anweisung im Konstruktor sein |
super.beschreibung() |
ruft die Methode der Oberklasse auf |
protected |
sichtbar in der eigenen Klasse und in allen Unterklassen |
Die Unterklasse überschreibt beschreibung(): Sie hat eine eigene Fassung, die die geerbte ersetzt. Innerhalb der neuen Fassung kommt man mit super. noch an die alte heran – so muss der gemeinsame Teil nicht noch einmal getippt werden.
Die Klassen Lehrer und Schueler haben keine Methode alterImJahr – und trotzdem funktioniert s.alterImJahr(2026).
Erkläre, warum.
Auflösung
Weil Schueler sie geerbt hat. Alles, was Person kann, kann jeder Schüler und jeder Lehrer auch – ohne dass es noch einmal geschrieben werden muss.
Genau das ist der Gewinn: Der gemeinsame Teil steht an einer Stelle. Ändert sich die Berechnung des Alters, ändert man Person – und alle Unterklassen ziehen mit.
Was in die Oberklasse gehört
Faustregel: In die Oberklasse gehört, was für alle Unterklassen gilt.
Prüfe deinen Entwurf mit dem Satz „ist ein“:
- „Ein Lehrer ist eine Person.“ ✓ Vererbung passt.
- „Ein Fahrrad ist ein Reifen.“ ✗ Vererbung passt nicht – hier gehört eine Assoziation hin („ein Fahrrad hat einen Reifen“).
Diese Unterscheidung – ist ein gegenüber hat ein – ist die wichtigste Entscheidung beim Modellieren.
Entscheide für jedes Paar: Vererbung oder Assoziation? Begründe mit dem Satztest.
a) Quadrat – Rechteck
b) Auto – Motor
c) Sparbuch – Bankkonto
d) Kurs – Schüler
e) Smartphone – Mobiltelefon
Auflösung
a) Vererbung: Ein Quadrat ist ein Rechteck (mit gleichen Seiten).
b) Assoziation: Ein Auto hat einen Motor. Es ist kein Motor.
c) Vererbung: Ein Sparbuch ist ein Bankkonto mit besonderen Regeln.
d) Assoziation: Ein Kurs hat Schüler. Ein Kurs ist kein Schüler.
e) Vererbung: Ein Smartphone ist ein Mobiltelefon – mit zusätzlichen Fähigkeiten.
Aufgabe 1: Konten mit Vererbung
Ein Girokonto darf bis zu einem vereinbarten Dispolimit ins Minus gehen. Ein Sparkonto darf das nicht, bekommt dafür aber Zinsen.
Beides sind Bankkonten. Setze die Vererbungshierarchie so um, dass alle Tests grün werden.
Tipp 1: Der Konstruktor der Unterklasse
Er muss zuerst den Konstruktor der Oberklasse aufrufen und danach sein eigenes Attribut setzen:
super(pBesitzer);
dispolimit = pDispolimit;
Tipp 2: Warum hat Sparkonto keine eigene hebeAb-Methode?
Weil die geerbte Fassung aus Konto schon genau das Richtige tut: Sie erlaubt nur Auszahlungen bis zum Kontostand.
Vererbung heißt nicht, dass man alles überschreiben muss – nur das, was anders sein soll.
Tipp 3: Die neue Grenze beim Girokonto
Statt pBetrag <= kontostand gilt jetzt pBetrag <= kontostand + dispolimit.
Aufgabe 2: Eine eigene Hierarchie
Modelliere eine Vererbungshierarchie für Gebäude.
a) Überlege, welche Eigenschaften alle Gebäude haben und was ein Wohnhaus, ein Bürogebäude und eine Schule jeweils zusätzlich auszeichnet.
b) Zeichne das Diagramm.
c) Prüfe jede Beziehung mit dem Satztest „ist ein“.
d) Setze mindestens die Oberklasse und eine Unterklasse um.
Zusatzaufgabe
Ein Feld vom Typ Konto[] kann Girokonten und Sparkonten aufnehmen – schließlich sind beide Konten.
a) Lege ein solches Feld an, fülle es mit beiden Sorten und berechne die Summe aller Kontostände.
b) Rufe in einer Schleife hebeAb(100) auf allen Konten auf. Beobachte: Bei welchen Objekten klappt es, bei welchen nicht?
c) Erkläre, welche der beiden Fassungen von hebeAb jeweils ausgeführt wird – und woher Java das zur Laufzeit weiß.
Dieses Verhalten heißt Polymorphie und ist eines der Hauptthemen im Lernpfad Erweiterungen.