/
/
·
·
/
/
·
·
  • Einführung
  • Das Problem
  • Die Begriffe
  • Code: extends (Java) und (Python)
  • Method-Dispatch: welche Methode wird aufgerufen?
  • Polymorphie: ein Typ, viele Formen
  • Override richtig: @Override und super.
  • abstract: Methoden ohne Body
  • Klausur-Tricks
  • Wo brauchst du Vererbung & Polymorphie?
ThemenProgrammiergrundlagenVererbung & Polymorphie
Programmiergrundlagen·3Lerneinheiten·34min·Stand02.08.2026

Vererbung & Polymorphie.

Vererbung ermöglicht es, eine Klasse von einer anderen abzuleiten und ihre Eigenschaften und Methoden zu übernehmen. Polymorphie heißt: derselbe Methodenaufruf verhält sich unterschiedlich, je nachdem welche konkrete Klasse das Objekt hat. Beispiel: tier.machGeraeusch() ruft bei einem Hund "Wuff!" und bei einer Katze "Miau", je nach echtem Objekttyp. Du lernst hier, wann Vererbung sinnvoll ist (is-a-Beziehung), wie extends und super funktionieren, wie Methoden mit @Override überschrieben werden, warum bei polymorphen Aufrufen der echte Objekttyp entscheidet (Dynamic Dispatch) und welche Sonderfälle static, private, final, abstract und Interfaces in Java haben. Zwei zentrale OOP-Mechanismen, die in jeder Klausur abgefragt werden.

Was du können musst:

  • extends (Java): class Hund extends Tier macht Hund zur Subklasse von Tier
  • super: Aufruf der Konstruktor- oder Methoden-Implementierung der Oberklasse
  • Override: Subklasse ersetzt eine Methode der Oberklasse, oft mit @Override-Annotation
  • abstract: abstract class kann nicht direkt mit new erzeugt werden. abstract method hat keinen Body und muss in konkreten Subklassen implementiert werden; eine abstrakte Subklasse darf abstrakte Methoden weiter offenlassen. (Häufiger Sprachfehler: man sagt nicht "Methode instanziieren", sondern "Klasse instanziieren" oder "Methode implementieren/überschreiben".)
  • Polymorphie: Variable vom Typ Tier kann auf ein Hund-Objekt zeigen; aufrufbar sind nur Methoden, die im deklarierten Typ Tier bekannt sind, bei überschriebenen Instanzmethoden läuft dann die Hund-Version

In Klausuren wirst du oft gefragt: welche Methode wird aufgerufen? wenn eine Variable vom Obertyp auf ein Subtyp-Objekt zeigt. Antwort: bei überschriebenen Instanzmethoden entscheidet der echte Objekttyp zur Laufzeit (dynamic dispatch). Ausnahmen: static (versteckt statt überschrieben), private (nicht überschreibbar), final (kann nicht überschrieben werden) sind nicht polymorph im Override-Sinn. Außerdem prüft Java Methodenaufrufe zuerst anhand des deklarierten Variablentyps: nur wenn die Methode dort bekannt ist, kann dynamic dispatch zur Override-Version greifen.

Du programmierst eine Tier-App. Du hast schon eine Klasse Hund:

class Hund {
    String name;
    int alter;
    void schlafen() { System.out.println("Zzz..."); }
    void machGeraeusch() { System.out.println("Wuff!"); }
}

Jetzt brauchst du Katze. Schreibst du die ganze Klasse nochmal? Mit name, alter, schlafen(), nochmal alles?

Vererbung sagt: nein. Pack das Gemeinsame in eine Basisklasse Tier, lass Hund und Katze davon erben.

class Tier {
    String name;
    int alter;
    void schlafen() { System.out.println("Zzz..."); }
}

class Hund extends Tier {
    void machGeraeusch() { System.out.println("Wuff!"); }
}

class Katze extends Tier {
    void machGeraeusch() { System.out.println("Miau"); }
}

Hund hat jetzt automatisch name, alter und schlafen(), geerbt von Tier. Plus seine eigene Methode machGeraeusch().

Das ist die Grundidee: gemeinsamer Code wandert nach oben, jede Unterklasse fügt nur ihr Spezifisches dazu.

BegriffWas es bedeutetBeispiel
Basisklasse / Superklasse / ParentDie Klasse oben in der HierarchieTier
Subklasse / Unterklasse / ChildDie Klasse, die erbtHund, Katze
extends (Java) / Klammern (Python)Vererbungs-Syntaxclass Hund extends Tier
VererbungSubklasse übernimmt die zugänglichen Felder und Methoden der Basisklasse. Private Felder sind im Objekt vorhanden, aber aus der Subklasse nicht direkt zugreifbar (Zugriff nur über public/protected Methoden der Basisklasse). Konstruktoren werden NICHT geerbt (weder direkt noch indirekt); jede Subklasse mit eigener Initialisierung oder parametrisiertem Basis-Konstruktor definiert eigene Konstruktoren, die typischerweise mit super(...) den Basisklassen-Konstruktor aufrufenHund hat name
OverrideSubklasse ersetzt eine geerbte Methode mit eigener VersionHund.machGeraeusch()
super (Java) / super() (Python)Zugriff auf die Methode/Konstruktor der Basisklassesuper(name, alter)
is-a Beziehung"Ein Hund ist ein Tier", Faustregel für VererbungHund is-a Tier ✓, Hund is-a Auto ✗

Vererbung modelliert "ist ein". Wenn du nicht sagen kannst "X ist ein Y", dann gehört X auch nicht in Y rein.

class Tier {
    String name;
    int alter;

    Tier(String name, int alter) {
        this.name = name;
        this.alter = alter;
    }

    void schlafen() {
        System.out.println(name + " schläft: Zzz...");
    }

    void machGeraeusch() {
        System.out.println("(unspezifisches Geräusch)");
    }
}

class Hund extends Tier {
    String rasse;

    Hund(String name, int alter, String rasse) {
        super(name, alter);   // Konstruktor der Basisklasse aufrufen
        this.rasse = rasse;
    }

    @Override
    void machGeraeusch() {     // überschreibt Tier.machGeraeusch()
        System.out.println(name + ": Wuff!");
    }
}

// Nutzung
Hund bello = new Hund("Bello", 4, "Labrador");
bello.schlafen();         // → "Bello schläft: Zzz..."  (geerbt von Tier)
bello.machGeraeusch();    // → "Bello: Wuff!"           (von Hund überschrieben)

In Python:

class Tier:
    def __init__(self, name, alter):
        self.name = name
        self.alter = alter

    def schlafen(self):
        print(f"{self.name} schläft: Zzz...")

    def mach_geraeusch(self):
        print("(unspezifisches Geräusch)")


class Hund(Tier):
    def __init__(self, name, alter, rasse):
        super().__init__(name, alter)
        self.rasse = rasse

    def mach_geraeusch(self):
        print(f"{self.name}: Wuff!")


bello = Hund("Bello", 4, "Labrador")
bello.schlafen()        # → "Bello schläft: Zzz..."
bello.mach_geraeusch()  # → "Bello: Wuff!"

super() ist der Schlüssel: damit ruft die Subklasse die Methode der Basisklasse auf, typischerweise im Konstruktor, um Felder der Basisklasse zu setzen.

Stell dir vor du rufst bello.machGeraeusch() auf. Welche Methode läuft?

Regel: Schau zuerst in der konkreten Klasse der Instanz (also Hund), dann wandere die Hierarchie hoch zur nächsten Basisklasse.

bello.machGeraeusch()
  ↓
1. Hat Hund eine machGeraeusch()?  → Ja → AUSFÜHREN ("Wuff!")

bello.schlafen()
  ↓
1. Hat Hund eine schlafen()?       → Nein
2. Hat Tier eine schlafen()?       → Ja → AUSFÜHREN ("Zzz...")

bello.fliegen()
  ↓
1. Hat Hund fliegen()?              → Nein
2. Hat Tier fliegen()?              → Nein
3. Compile-Fehler! (Java)
   AttributeError! (Python)

Erst die spezifischste Klasse, dann nach oben, die erste passende Methode gewinnt.

Wichtig zum Zusammenspiel mit Polymorphie: Java prüft zur Compile-Zeit, ob die Methode im deklarierten Typ der Variable bekannt ist. Nur wenn ja, greift zur Laufzeit Dynamic Dispatch zur Override-Version. Beispiel: bei Tier x = new Hund(...); x.fliegen() ist es ein Compile-Fehler, weil Tier keine fliegen() kennt, obwohl Hund vielleicht eine hätte. Im Interaktiv-Tab kannst du das live durchspielen.

Das ist der wirkliche Trick. Du kannst eine Variable vom Typ Tier haben, die in Wirklichkeit einen Hund speichert:

Tier x = new Hund("Bello", 4, "Labrador");
x.machGeraeusch();   // → "Bello: Wuff!"

Was? x ist als Tier deklariert, aber Wuff! kommt raus? Ja, das ist dynamischer Dispatch:

Welche Methode aufgerufen wird, entscheidet der echte Typ des Objekts (Hund), nicht der deklarierte Typ der Variable (Tier).

Das nennt man Polymorphie, "viele Formen". Eine Tier-Variable kann verschiedene Formen annehmen (Hund, Katze, Vogel) und sich entsprechend verhalten.

Tier[] zoo = {
    new Hund("Bello", 4, "Labrador"),
    new Katze("Whiskers", 3),
    new Vogel("Tweety", 2)
};

for (Tier t : zoo) {
    t.machGeraeusch();  // jedes Tier sein eigenes Geräusch
}
// Output:
//   Bello: Wuff!
//   Whiskers: Miau
//   Tweety: Tschilp

Polymorphie ist der Hauptgrund warum Vererbung mächtig ist: gleicher Code, unterschiedliches Verhalten je nach echtem Typ.

In Java schreibt man @Override über eine überschriebene Methode. Das ist optional, aber stark empfohlen, der Compiler prüft, dass die Methode wirklich existiert in der Basisklasse.

class Hund extends Tier {
    @Override
    void machGeraeusch() {  // Compiler: passt das zu Tier.machGeraeusch()? Ja!
        System.out.println("Wuff!");
    }
}

Verschreibst du dich (mach_Geraeusch() mit Tippfehler), wird ohne @Override einfach eine neue Methode angelegt, Bug auf Lebenszeit. Mit @Override schreit der Compiler.

In Python gibt es kein Java-gleiches Compile-Time-@Override. Ab Python 3.12 gibt es typing.override als Decorator für statische Typchecker, zur Laufzeit bleibt Python aber dynamisch und erzwingt Override nicht.

super. innerhalb einer Override

Manchmal willst du das alte Verhalten ergänzen, nicht ersetzen:

class Hund extends Tier {
    @Override
    void schlafen() {
        super.schlafen();              // Tier.schlafen() rufen
        System.out.println("(im Korb)");
    }
}
// Hund.schlafen() → "Bello schläft: Zzz..." + "(im Korb)"

super.methode() heißt: "Ruf die Version der Basisklasse auf." Häufig in Konstruktoren (super(name, alter)) und beim Erweitern statt Ersetzen.

Manchmal soll die Basisklasse erzwingen, dass jede Subklasse eine bestimmte Methode hat, ohne selbst zu wissen, was die tut.

abstract class Tier {
    String name;

    abstract void machGeraeusch();   // kein Body; konkrete Subklassen MÜSSEN implementieren

    void schlafen() {                 // normal, kann geerbt werden
        System.out.println(name + " schläft");
    }
}

class Hund extends Tier {
    @Override
    void machGeraeusch() {
        System.out.println("Wuff!");  // Pflicht: Compiler erzwingt es
    }
}

new Tier();   // FEHLER: kann nicht instantiiert werden, Tier ist abstract
new Hund();   // OK

Eine abstrakte Klasse kann nicht direkt instantiiert werden, nur ihre konkreten Subklassen. Sie definiert ein Pflichtprogramm. Wichtig: eine abstrakte Klasse kann sowohl abstrakte Methoden (ohne Body, MUSS überschrieben werden) als auch konkrete Methoden (mit Body, wird geerbt) enthalten.

Trick 1, is-a vs has-a: Vererbung ist "ist ein". Wenn du eher sagen würdest "hat ein", brauchst du Komposition (Feld vom Typ X), nicht Vererbung.

Hund is-a Tier         ✓ → Vererbung
Auto has-a Motor       ✓ → Komposition (Auto hat ein Motor-Feld)
Auto is-a Motor        ✗ → falsche Modellierung

Trick 2, Override-Regel (Java): Eine Methode in der Subklasse überschreibt nur, wenn:

  • gleicher Name
  • gleiche Parameter-Liste (sonst ist es eine Überladung, anderes Konzept)
  • gleicher oder kovarianter Rückgabetyp
  • Sichtbarkeit nicht einschränken (z. B. von public auf protected ist nicht erlaubt)
  • geprüfte Exceptions nicht breiter machen

Trick 3, Konstruktor wird NICHT geerbt. Du musst in der Subklasse einen eigenen Konstruktor schreiben und mit super(...) den Basis-Konstruktor aufrufen.

Trick 4, Polymorphie-Vergleich (nur als Sprachen-Vergleich, falls deine Klausur mehrere Sprachen erwähnt):

  • Java: dynamic dispatch für überschreibbare Instanzmethoden, nicht für static/private/final.
  • Python: dynamische Methodensuche über die MRO (Method Resolution Order).
  • C++: dynamic dispatch nur bei virtual-Methoden.

Klausur-Frage: "ist equals() in Java polymorph?" → Ja. Da Object.equals() eine public instance method ist (nicht static/private/final), wird sie polymorph überschrieben, z. B. in String, ArrayList, eigenen Klassen.

Trick 5, Diamant-Problem: Mehrfachvererbung von Klassen ist in Java verboten (nur 1 extends). Mehrere Interfaces sind erlaubt; seit Java 8 können Interfaces default-Methoden mit Body haben, bei Konflikten muss die Klasse eindeutig überschreiben oder auflösen. Python erlaubt Mehrfachvererbung. In Python 3 sind alle Klassen new-style, und die MRO (Method Resolution Order, C3-Linearisierung) löst Konflikte über eine feste Suchreihenfolge der Klassenhierarchie. (Python 2 old-style classes nutzten einfache Tiefensuche, sind aber seit 2020 EOL.)

Trick 6, Java spezifisch: Object ist Vater aller Klassen. Jede Klasse erbt implizit von java.lang.Object, daher hat jedes Objekt toString(), equals(), hashCode().

Trick 7, instanceof: prüft den echten Typ zur Laufzeit:

Tier t = new Hund(...);
t instanceof Hund   // true, echter Typ ist Hund
t instanceof Tier   // true, Hund ist auch ein Tier (Vererbungskette)
t instanceof Katze  // false
  • GUI-Frameworks: Button extends Widget, TextField extends Widget, alle haben render() polymorph
  • Game-Entwicklung: Enemy extends GameObject, viele Enemy-Subtypes mit eigenem update()
  • Servlets / Spring: MyController extends BaseController mit überschriebenen Endpoints
  • Sammlungen: ArrayList implements List, LinkedList implements List, gleiches Interface, andere Implementierung
  • Streams in Java: FileInputStream extends InputStream, BufferedInputStream extends InputStream

Faustregel: Wenn du in der Klausur sagen sollst, ob Vererbung passt, frag dich "ist X ein Y?" Wenn ja, vererbe. Wenn nein, finde was anderes (Komposition, Interface, etc.).

Drei Tier-Klassen erben von Tier. Jede überschreibt machGeraeusch(), schlafen() wird geerbt (nicht überschrieben), fliegen() gibt's nur in Vogel.

Probier folgendes:

  • h.machGeraeusch(), Dispatch findet Methode in Hund (überschrieben), Output "Wuff!"
  • k.schlafen(), Dispatch findet nichts in Katze, geht hoch zu Tier, Output "Zzz..."
  • h.fliegen(), Dispatch findet nichts in Hund, nichts in Tier → Fehler, Methode existiert nicht
  • v.machGeraeusch(), Vogel überschreibt, Output "Tschilp"

Beobachte den Dispatch-Pfad: rote Box = hier gefunden, durchgestrichene Boxen = hier gesucht aber nicht gefunden.

Lade Visualisierung...

Faustregel zum Mitnehmen: Bei überschreibbaren Instanzmethoden geht die Methodensuche vom echten Typ nach oben. Suche zuerst in der konkreten Klasse, wandere dann durch extends hoch. Erste passende Methode wird ausgeführt, das ist der dynamische Dispatch-Mechanismus, die Basis von Polymorphie. (Sonderfälle: static, private, final sind nicht polymorph.)


Drei interaktive Demos zu den häufigsten Klausur-Stolperern bei Vererbung und Polymorphie: Dynamic Dispatch (welche Methode wird aufgerufen, wenn die Variable als Tier deklariert ist, aber auf einen Hund zeigt?), Constructor-Chaining mit super() (Reihenfolge: Basisklasse-Konstruktor läuft zuerst), und Polymorphes Array mit Tier-Array, das verschiedene konkrete Typen enthält. Klicke auf Step oder Auto.

1. Dynamic Dispatch: welche Methode läuft?

Lade Visualisierung...

2. Constructor-Chaining: super() läuft ZUERST

Wenn eine Subklasse eine Instanz erzeugt, läuft der Basisklassen-Konstruktor vor dem eigenen Konstruktor-Body. super(...) macht das explizit; ohne expliziten Aufruf nimmt Java automatisch den No-Args-Konstruktor der Basisklasse.

Lade Visualisierung...

3. Polymorphes Array: ein Typ, viele Formen

Ein Array vom Typ Tier[] kann Hunde, Katzen und Vögel halten. Die for-Schleife ruft machGeraeusch() auf, und Dynamic Dispatch sorgt dafür, dass die richtige Methode pro Element läuft.

Lade Visualisierung...

Anmelden, um den Fortschritt zu speichern.

Nächster Schritt

Wenn du fertig bist: jetzt üben.

Aktives Abrufen festigt Wissen schneller als nochmal lesen.

War das hilfreich?

Verwandte Themen

  • Variablen und Datentypen
  • Bedingungen
  • Schleifen
  • Funktionen
  • Rekursion

Folgt

  • Exception Handling
  • Interfaces
  • Komposition vs. Vererbung

Tools

Bald: Karteikarten · Spaced-Repetition · Mind-Map-Export

Fachliche Qualität
S-Tier · GoldstandardZuletzt geprüft am 18.05.2026

Diese Lerneinheit wurde für typische Bachelor-Klausuren konzipiert. So prüfen wir · Fehler entdeckt? Melde ihn uns oder markiere die fragliche Stelle direkt im Text oben.

Klausur-ÜbersichtKomplette Übersicht: alle Tabs als linearer Text zum Lernen
▾

Alle Tabs der Lerneinheit (Erklärung · Interaktiv · Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).

Inhalt dieser Übersicht

  1. Erklärung(Erklärung)
  2. Interaktiv(Visualisierung / Interaktiv)
  3. Quiz(Quiz / Klausurfragen)
Teil 1·Erklärung

Erklärung

Vererbung ermöglicht es, eine Klasse von einer anderen abzuleiten und ihre Eigenschaften und Methoden zu übernehmen. Polymorphie heißt: derselbe Methodenaufruf verhält sich unterschiedlich, je nachdem welche konkrete Klasse das Objekt hat. Beispiel: tier.machGeraeusch() ruft bei einem Hund "Wuff!" und bei einer Katze "Miau", je nach echtem Objekttyp. Du lernst hier, wann Vererbung sinnvoll ist (is-a-Beziehung), wie extends und super funktionieren, wie Methoden mit @Override überschrieben werden, warum bei polymorphen Aufrufen der echte Objekttyp entscheidet (Dynamic Dispatch) und welche Sonderfälle static, private, final, abstract und Interfaces in Java haben. Zwei zentrale OOP-Mechanismen, die in jeder Klausur abgefragt werden.

Was du können musst:

  • extends (Java): class Hund extends Tier macht Hund zur Subklasse von Tier
  • super: Aufruf der Konstruktor- oder Methoden-Implementierung der Oberklasse
  • Override: Subklasse ersetzt eine Methode der Oberklasse, oft mit @Override-Annotation
  • abstract: abstract class kann nicht direkt mit new erzeugt werden. abstract method hat keinen Body und muss in konkreten Subklassen implementiert werden; eine abstrakte Subklasse darf abstrakte Methoden weiter offenlassen. (Häufiger Sprachfehler: man sagt nicht "Methode instanziieren", sondern "Klasse instanziieren" oder "Methode implementieren/überschreiben".)
  • Polymorphie: Variable vom Typ Tier kann auf ein Hund-Objekt zeigen; aufrufbar sind nur Methoden, die im deklarierten Typ Tier bekannt sind, bei überschriebenen Instanzmethoden läuft dann die Hund-Version

In Klausuren wirst du oft gefragt: welche Methode wird aufgerufen? wenn eine Variable vom Obertyp auf ein Subtyp-Objekt zeigt. Antwort: bei überschriebenen Instanzmethoden entscheidet der echte Objekttyp zur Laufzeit (dynamic dispatch). Ausnahmen: static (versteckt statt überschrieben), private (nicht überschreibbar), final (kann nicht überschrieben werden) sind nicht polymorph im Override-Sinn. Außerdem prüft Java Methodenaufrufe zuerst anhand des deklarierten Variablentyps: nur wenn die Methode dort bekannt ist, kann dynamic dispatch zur Override-Version greifen.

Das Problem

Du programmierst eine Tier-App. Du hast schon eine Klasse Hund:

class Hund {
    String name;
    int alter;
    void schlafen() { System.out.println("Zzz..."); }
    void machGeraeusch() { System.out.println("Wuff!"); }
}

Jetzt brauchst du Katze. Schreibst du die ganze Klasse nochmal? Mit name, alter, schlafen(), nochmal alles?

Vererbung sagt: nein. Pack das Gemeinsame in eine Basisklasse Tier, lass Hund und Katze davon erben.

class Tier {
    String name;
    int alter;
    void schlafen() { System.out.println("Zzz..."); }
}

class Hund extends Tier {
    void machGeraeusch() { System.out.println("Wuff!"); }
}

class Katze extends Tier {
    void machGeraeusch() { System.out.println("Miau"); }
}

Hund hat jetzt automatisch name, alter und schlafen(), geerbt von Tier. Plus seine eigene Methode machGeraeusch().

Das ist die Grundidee: gemeinsamer Code wandert nach oben, jede Unterklasse fügt nur ihr Spezifisches dazu.

Die Begriffe

BegriffWas es bedeutetBeispiel
Basisklasse / Superklasse / ParentDie Klasse oben in der HierarchieTier
Subklasse / Unterklasse / ChildDie Klasse, die erbtHund, Katze
extends (Java) / Klammern (Python)Vererbungs-Syntaxclass Hund extends Tier
VererbungSubklasse übernimmt die zugänglichen Felder und Methoden der Basisklasse. Private Felder sind im Objekt vorhanden, aber aus der Subklasse nicht direkt zugreifbar (Zugriff nur über public/protected Methoden der Basisklasse). Konstruktoren werden NICHT geerbt (weder direkt noch indirekt); jede Subklasse mit eigener Initialisierung oder parametrisiertem Basis-Konstruktor definiert eigene Konstruktoren, die typischerweise mit super(...) den Basisklassen-Konstruktor aufrufenHund hat name
OverrideSubklasse ersetzt eine geerbte Methode mit eigener VersionHund.machGeraeusch()
super (Java) / super() (Python)Zugriff auf die Methode/Konstruktor der Basisklassesuper(name, alter)
is-a Beziehung"Ein Hund ist ein Tier", Faustregel für VererbungHund is-a Tier ✓, Hund is-a Auto ✗

Vererbung modelliert "ist ein". Wenn du nicht sagen kannst "X ist ein Y", dann gehört X auch nicht in Y rein.

Code: extends (Java) und (Python)

class Tier {
    String name;
    int alter;

    Tier(String name, int alter) {
        this.name = name;
        this.alter = alter;
    }

    void schlafen() {
        System.out.println(name + " schläft: Zzz...");
    }

    void machGeraeusch() {
        System.out.println("(unspezifisches Geräusch)");
    }
}

class Hund extends Tier {
    String rasse;

    Hund(String name, int alter, String rasse) {
        super(name, alter);   // Konstruktor der Basisklasse aufrufen
        this.rasse = rasse;
    }

    @Override
    void machGeraeusch() {     // überschreibt Tier.machGeraeusch()
        System.out.println(name + ": Wuff!");
    }
}

// Nutzung
Hund bello = new Hund("Bello", 4, "Labrador");
bello.schlafen();         // → "Bello schläft: Zzz..."  (geerbt von Tier)
bello.machGeraeusch();    // → "Bello: Wuff!"           (von Hund überschrieben)

In Python:

class Tier:
    def __init__(self, name, alter):
        self.name = name
        self.alter = alter

    def schlafen(self):
        print(f"{self.name} schläft: Zzz...")

    def mach_geraeusch(self):
        print("(unspezifisches Geräusch)")


class Hund(Tier):
    def __init__(self, name, alter, rasse):
        super().__init__(name, alter)
        self.rasse = rasse

    def mach_geraeusch(self):
        print(f"{self.name}: Wuff!")


bello = Hund("Bello", 4, "Labrador")
bello.schlafen()        # → "Bello schläft: Zzz..."
bello.mach_geraeusch()  # → "Bello: Wuff!"

super() ist der Schlüssel: damit ruft die Subklasse die Methode der Basisklasse auf, typischerweise im Konstruktor, um Felder der Basisklasse zu setzen.

Method-Dispatch: welche Methode wird aufgerufen?

Stell dir vor du rufst bello.machGeraeusch() auf. Welche Methode läuft?

Regel: Schau zuerst in der konkreten Klasse der Instanz (also Hund), dann wandere die Hierarchie hoch zur nächsten Basisklasse.

bello.machGeraeusch()
  ↓
1. Hat Hund eine machGeraeusch()?  → Ja → AUSFÜHREN ("Wuff!")

bello.schlafen()
  ↓
1. Hat Hund eine schlafen()?       → Nein
2. Hat Tier eine schlafen()?       → Ja → AUSFÜHREN ("Zzz...")

bello.fliegen()
  ↓
1. Hat Hund fliegen()?              → Nein
2. Hat Tier fliegen()?              → Nein
3. Compile-Fehler! (Java)
   AttributeError! (Python)

Erst die spezifischste Klasse, dann nach oben, die erste passende Methode gewinnt.

Wichtig zum Zusammenspiel mit Polymorphie: Java prüft zur Compile-Zeit, ob die Methode im deklarierten Typ der Variable bekannt ist. Nur wenn ja, greift zur Laufzeit Dynamic Dispatch zur Override-Version. Beispiel: bei Tier x = new Hund(...); x.fliegen() ist es ein Compile-Fehler, weil Tier keine fliegen() kennt, obwohl Hund vielleicht eine hätte. Im Interaktiv-Tab kannst du das live durchspielen.

Polymorphie: ein Typ, viele Formen

Das ist der wirkliche Trick. Du kannst eine Variable vom Typ Tier haben, die in Wirklichkeit einen Hund speichert:

Tier x = new Hund("Bello", 4, "Labrador");
x.machGeraeusch();   // → "Bello: Wuff!"

Was? x ist als Tier deklariert, aber Wuff! kommt raus? Ja, das ist dynamischer Dispatch:

Welche Methode aufgerufen wird, entscheidet der echte Typ des Objekts (Hund), nicht der deklarierte Typ der Variable (Tier).

Das nennt man Polymorphie, "viele Formen". Eine Tier-Variable kann verschiedene Formen annehmen (Hund, Katze, Vogel) und sich entsprechend verhalten.

Tier[] zoo = {
    new Hund("Bello", 4, "Labrador"),
    new Katze("Whiskers", 3),
    new Vogel("Tweety", 2)
};

for (Tier t : zoo) {
    t.machGeraeusch();  // jedes Tier sein eigenes Geräusch
}
// Output:
//   Bello: Wuff!
//   Whiskers: Miau
//   Tweety: Tschilp

Polymorphie ist der Hauptgrund warum Vererbung mächtig ist: gleicher Code, unterschiedliches Verhalten je nach echtem Typ.

Override richtig: @Override und super.

In Java schreibt man @Override über eine überschriebene Methode. Das ist optional, aber stark empfohlen, der Compiler prüft, dass die Methode wirklich existiert in der Basisklasse.

class Hund extends Tier {
    @Override
    void machGeraeusch() {  // Compiler: passt das zu Tier.machGeraeusch()? Ja!
        System.out.println("Wuff!");
    }
}

Verschreibst du dich (mach_Geraeusch() mit Tippfehler), wird ohne @Override einfach eine neue Methode angelegt, Bug auf Lebenszeit. Mit @Override schreit der Compiler.

In Python gibt es kein Java-gleiches Compile-Time-@Override. Ab Python 3.12 gibt es typing.override als Decorator für statische Typchecker, zur Laufzeit bleibt Python aber dynamisch und erzwingt Override nicht.

super. innerhalb einer Override

Manchmal willst du das alte Verhalten ergänzen, nicht ersetzen:

class Hund extends Tier {
    @Override
    void schlafen() {
        super.schlafen();              // Tier.schlafen() rufen
        System.out.println("(im Korb)");
    }
}
// Hund.schlafen() → "Bello schläft: Zzz..." + "(im Korb)"

super.methode() heißt: "Ruf die Version der Basisklasse auf." Häufig in Konstruktoren (super(name, alter)) und beim Erweitern statt Ersetzen.

abstract: Methoden ohne Body

Manchmal soll die Basisklasse erzwingen, dass jede Subklasse eine bestimmte Methode hat, ohne selbst zu wissen, was die tut.

abstract class Tier {
    String name;

    abstract void machGeraeusch();   // kein Body; konkrete Subklassen MÜSSEN implementieren

    void schlafen() {                 // normal, kann geerbt werden
        System.out.println(name + " schläft");
    }
}

class Hund extends Tier {
    @Override
    void machGeraeusch() {
        System.out.println("Wuff!");  // Pflicht: Compiler erzwingt es
    }
}

new Tier();   // FEHLER: kann nicht instantiiert werden, Tier ist abstract
new Hund();   // OK

Eine abstrakte Klasse kann nicht direkt instantiiert werden, nur ihre konkreten Subklassen. Sie definiert ein Pflichtprogramm. Wichtig: eine abstrakte Klasse kann sowohl abstrakte Methoden (ohne Body, MUSS überschrieben werden) als auch konkrete Methoden (mit Body, wird geerbt) enthalten.

Klausur-Tricks

Trick 1, is-a vs has-a: Vererbung ist "ist ein". Wenn du eher sagen würdest "hat ein", brauchst du Komposition (Feld vom Typ X), nicht Vererbung.

Hund is-a Tier         ✓ → Vererbung
Auto has-a Motor       ✓ → Komposition (Auto hat ein Motor-Feld)
Auto is-a Motor        ✗ → falsche Modellierung

Trick 2, Override-Regel (Java): Eine Methode in der Subklasse überschreibt nur, wenn:

  • gleicher Name
  • gleiche Parameter-Liste (sonst ist es eine Überladung, anderes Konzept)
  • gleicher oder kovarianter Rückgabetyp
  • Sichtbarkeit nicht einschränken (z. B. von public auf protected ist nicht erlaubt)
  • geprüfte Exceptions nicht breiter machen

Trick 3, Konstruktor wird NICHT geerbt. Du musst in der Subklasse einen eigenen Konstruktor schreiben und mit super(...) den Basis-Konstruktor aufrufen.

Trick 4, Polymorphie-Vergleich (nur als Sprachen-Vergleich, falls deine Klausur mehrere Sprachen erwähnt):

  • Java: dynamic dispatch für überschreibbare Instanzmethoden, nicht für static/private/final.
  • Python: dynamische Methodensuche über die MRO (Method Resolution Order).
  • C++: dynamic dispatch nur bei virtual-Methoden.

Klausur-Frage: "ist equals() in Java polymorph?" → Ja. Da Object.equals() eine public instance method ist (nicht static/private/final), wird sie polymorph überschrieben, z. B. in String, ArrayList, eigenen Klassen.

Trick 5, Diamant-Problem: Mehrfachvererbung von Klassen ist in Java verboten (nur 1 extends). Mehrere Interfaces sind erlaubt; seit Java 8 können Interfaces default-Methoden mit Body haben, bei Konflikten muss die Klasse eindeutig überschreiben oder auflösen. Python erlaubt Mehrfachvererbung. In Python 3 sind alle Klassen new-style, und die MRO (Method Resolution Order, C3-Linearisierung) löst Konflikte über eine feste Suchreihenfolge der Klassenhierarchie. (Python 2 old-style classes nutzten einfache Tiefensuche, sind aber seit 2020 EOL.)

Trick 6, Java spezifisch: Object ist Vater aller Klassen. Jede Klasse erbt implizit von java.lang.Object, daher hat jedes Objekt toString(), equals(), hashCode().

Trick 7, instanceof: prüft den echten Typ zur Laufzeit:

Tier t = new Hund(...);
t instanceof Hund   // true, echter Typ ist Hund
t instanceof Tier   // true, Hund ist auch ein Tier (Vererbungskette)
t instanceof Katze  // false

Wo brauchst du Vererbung & Polymorphie?

  • GUI-Frameworks: Button extends Widget, TextField extends Widget, alle haben render() polymorph
  • Game-Entwicklung: Enemy extends GameObject, viele Enemy-Subtypes mit eigenem update()
  • Servlets / Spring: MyController extends BaseController mit überschriebenen Endpoints
  • Sammlungen: ArrayList implements List, LinkedList implements List, gleiches Interface, andere Implementierung
  • Streams in Java: FileInputStream extends InputStream, BufferedInputStream extends InputStream

Faustregel: Wenn du in der Klausur sagen sollst, ob Vererbung passt, frag dich "ist X ein Y?" Wenn ja, vererbe. Wenn nein, finde was anderes (Komposition, Interface, etc.).

Teil 2·Visualisierung / Interaktiv

Interaktiv

Hierarchie-Spielwiese

Drei Tier-Klassen erben von Tier. Jede überschreibt machGeraeusch(), schlafen() wird geerbt (nicht überschrieben), fliegen() gibt's nur in Vogel.

Probier folgendes:

  • h.machGeraeusch(), Dispatch findet Methode in Hund (überschrieben), Output "Wuff!"
  • k.schlafen(), Dispatch findet nichts in Katze, geht hoch zu Tier, Output "Zzz..."
  • h.fliegen(), Dispatch findet nichts in Hund, nichts in Tier → Fehler, Methode existiert nicht
  • v.machGeraeusch(), Vogel überschreibt, Output "Tschilp"

Beobachte den Dispatch-Pfad: rote Box = hier gefunden, durchgestrichene Boxen = hier gesucht aber nicht gefunden.

Interaktive Visualisierung

Visualisiert Vererbungs-Hierarchien mit überschriebenen Methoden und dynamischem Dispatch.

Faustregel zum Mitnehmen: Bei überschreibbaren Instanzmethoden geht die Methodensuche vom echten Typ nach oben. Suche zuerst in der konkreten Klasse, wandere dann durch extends hoch. Erste passende Methode wird ausgeführt, das ist der dynamische Dispatch-Mechanismus, die Basis von Polymorphie. (Sonderfälle: static, private, final sind nicht polymorph.)


Code-Stepper: Klausur-Klassiker durchspielen

Drei interaktive Demos zu den häufigsten Klausur-Stolperern bei Vererbung und Polymorphie: Dynamic Dispatch (welche Methode wird aufgerufen, wenn die Variable als Tier deklariert ist, aber auf einen Hund zeigt?), Constructor-Chaining mit super() (Reihenfolge: Basisklasse-Konstruktor läuft zuerst), und Polymorphes Array mit Tier-Array, das verschiedene konkrete Typen enthält. Klicke auf Step oder Auto.

1. Dynamic Dispatch: welche Methode läuft?

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

2. Constructor-Chaining: super() läuft ZUERST

Wenn eine Subklasse eine Instanz erzeugt, läuft der Basisklassen-Konstruktor vor dem eigenen Konstruktor-Body. super(...) macht das explizit; ohne expliziten Aufruf nimmt Java automatisch den No-Args-Konstruktor der Basisklasse.

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

3. Polymorphes Array: ein Typ, viele Formen

Ein Array vom Typ Tier[] kann Hunde, Katzen und Vögel halten. Die for-Schleife ruft machGeraeusch() auf, und Dynamic Dispatch sorgt dafür, dass die richtige Methode pro Element läuft.

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

Teil 3·Quiz / Klausurfragen

Quiz

Klausurfragen mit Lösungen (8)

F1.Welche der folgenden Beziehungen rechtfertigt Vererbung (is-a)?

Antwort: Hund und Tier

Erklärung: Vererbung modelliert 'ist ein' (is-a). 'Hund ist ein Tier' ✓. Die anderen sind 'hat ein' (has-a), Komposition wäre richtig: Auto hat einen Motor, Mensch hat eine Adresse.

F2.Was passiert, wenn eine Subklasse eine Methode der Basisklasse mit gleicher Signatur definiert?

Antwort: Die neue Methode überschreibt die alte (Override)

Erklärung: Das ist **Override**: gleiche Signatur in der Subklasse ersetzt die geerbte Methode. Bei Aufrufen auf einer Subklassen-Instanz wird die neue Version genommen, egal ob die Variable als Sub- oder Basisklasse deklariert ist (dynamischer Dispatch).

F3.In Java: was bewirkt super(name, alter) im Konstruktor einer Subklasse?

Antwort: Ruft den Konstruktor der Basisklasse auf, um geerbte Felder zu initialisieren

Erklärung: super(...) ruft den Konstruktor der Basisklasse mit den angegebenen Argumenten auf. Damit werden die geerbten Felder ordentlich initialisiert. Konstruktoren werden NICHT geerbt, daher braucht jede Subklasse einen eigenen.

F4.Was gibt bello.machGeraeusch() aus, wenn Hund machGeraeusch() mit 'Wuff!' überschreibt?
Tier bello = new Hund("Bello", 4, "Labrador");
bello.machGeraeusch();

Antwort: Wuff!, weil dynamischer Dispatch den echten Typ Hund nimmt

Erklärung: Polymorphie / dynamischer Dispatch: Java guckt zur Laufzeit auf den **echten** Typ des Objekts (Hund), nicht auf die Variablen-Deklaration (Tier). Hund hat machGeraeusch() überschrieben → 'Wuff!' wird ausgegeben. **Voraussetzung**: Die Methode muss im **deklarierten** Typ (hier `Tier`) bekannt sein, sonst wäre der Aufruf bereits Compile-Fehler. Dynamic dispatch entscheidet nur, **welche** Override-Version einer im Typ bekannten Methode läuft.

F5.Eine Klasse ist als abstract deklariert. Was bedeutet das?

Antwort: Sie kann nicht direkt instantiiert werden, nur konkrete Subklassen können es

Erklärung: abstract heißt: kein direktes 'new'. Die Klasse beschreibt ein Konzept, das erst durch konkrete Subklassen Form annimmt. Sie kann sehr wohl Felder und Methoden haben, und meist auch abstract-Methoden, die Subklassen implementieren MÜSSEN.

F6.Was passiert beim Method-Dispatch, wenn die Methode weder in der konkreten Klasse noch in einer Basisklasse existiert?

Antwort: Compile-Fehler in Java, AttributeError zur Laufzeit in Python

Erklärung: In Java findet der Compiler den Aufruf gar nicht erst zulässig, Build schlägt fehl. In Python merkt's der Interpreter erst zur Laufzeit (AttributeError), weil Python dynamisch typisiert ist. So oder so: kein automatisches Erstellen, kein null.

F7.Warum erlaubt Java keine Mehrfachvererbung von Klassen (also nicht class C extends A, B)?

Antwort: Wegen des Diamant-Problems: Konflikt, wenn A und B beide eine Methode m() haben, welche soll C erben?

Erklärung: Diamant-Problem: erbt C von A und B, und beide haben m(), welche soll gelten? Java verbietet **Klassen**-Mehrfachvererbung. Mehrere **Interfaces** sind erlaubt, historisch hatten sie keinen Body, aber **seit Java 8** können Interfaces \`default\`-Methoden mit Implementierung haben. Bei Default-Method-Konflikten muss die Klasse eindeutig überschreiben/auflösen. Python erlaubt's und löst per **MRO** (in Python 3 immer C3-Linearisierung).

F8.Was ist Polymorphie in einem Satz?

Antwort: Eine Variable vom Basisklassen-Typ kann sich je nach echtem Objekttyp unterschiedlich verhalten

Erklärung: Polymorphie = 'viele Formen'. Eine Tier-Variable kann ein Hund, eine Katze, ein Vogel sein, bei einem Methodenaufruf wird die jeweils passende Override-Version ausgeführt. Das macht Code flexibel: gleicher Aufruf, unterschiedliches Verhalten je nach Typ.

Zur KategorieProgrammiergrundlagen.Mehr Themen entdeckenZum Themen-Hub.

UniProMax ist eine themenbasierte Lernplattform für Studierende an deutschen Unis.

Wir glauben, dass Verstehen besser ist als Auswendiglernen. Wir bauen Lerneinheiten die zeigen statt erzählen. Code, Visualisierung, Quiz. Auf Deutsch.

Marke

UniProMaxUniProMax

Themenbasiert, visuell, interaktiv.

Inhalte

  • Alle Themen (Hub)
  • Programmiergrundlagen
  • Algorithmen
  • Mathematik
  • Statistik
  • Datenbanken
  • Rechnungswesen
  • VWL

Studiengang-Filter

  • Informatik
  • Wirtschaftsinformatik
  • BWL
  • Data Science
  • VWL
  • Wirtschaftsingenieurwesen
  • Mathe
  • Psychologie
  • weitere Studiengänge folgen

Plattform

  • Mein Fortschritt
  • Impressum
  • Datenschutz
© 2026 UniProMaxAlle Systeme onlinev0.2 / Sommersemester 2026
UniProMaxUniProMaxUniProMaxUniProMax