((Hund)t).auge = 3; → Cast nötig, um Attribute der Unterklasse zu nutzen
⚠️ Wichtige Ergänzung: Overriding vs. Overloading
Overriding (Überschreiben)
Overloading (Überladen)
Was?
Gleicher Name + gleiche Parameter in Unterklassen
Gleicher Name, unterschiedliche Parameterliste — auch durch Vererbung möglich
Bindung
Dynamisch → JVM entscheidet zur Laufzeit
Statisch → Compiler entscheidet zur Kompilierzeit
Beispiel
Hund.laut() überschreibt Tier.laut()
add(int) und add(String) nebeneinander
💡 Merksatz: Überladene Methoden werden statisch gebunden. Überschriebene Methoden werden dynamisch gebunden.
⚠️ Typische Prüfungsfalle: Casting & instanceof
Wenn Referenztyp und Objekttyp auseinandergehen, musst du casten, um Unterklasse-spezifisches zu nutzen:
Tier t = new Hund(); // Referenztyp: Tier | Objekttyp: Hund// ❌ Compiler-Error: t.bellen() geht nicht (Compiler sieht nur Tier)// t.bellen();// ✅ Erst prüfen, ob es ein Hund ist, dann castenif (t instanceof Hund) { Hund h = (Hund) t; // Cast nötig! h.bellen(); // Jetzt funktioniert's}// ⚠️ Ohne Prüfung: ClassCastException beim Cast zu Katze!// Katze k = (Katze) t; // 💥 Runtime-Error, weil t ein Hund ist!
💡 Merksatz:instanceof prüft den Objekttyp (Laufzeittyp), nicht den Referenztyp. Der Compiler entscheidet beim Cast nur, ob es möglicherweise funktioniert — die JVM führt es erst zur Laufzeit aus.
Warum Polymorphie?
Du schreibst Code für Tier und er funktioniert automatisch mit allen Unterklassen — auch neuen, die du später erstellst. (Open-Closed Principle)
2. Checked vs. Unchecked Exceptions
Checked
Unchecked
Müssen behandelt werden?
✅ Ja (try-catch oder throws)
❌ Nein
Wer wirft sie?
Programmierer (throw new ...)
JVM automatisch (bei Bugs) oder Programmierer bewusst
Oberklasse
Exception
RuntimeException
Beispiele
IOException, eigene Exceptions
ArithmeticException, NullPointerException, auch bewusst definierteRuntimeException-Unterklassen
Wichtige Korrektur zur Vereinfachung
“Checked = Fehler von außen, Unchecked = Fehler im Code” ❌
Diese Aussage ist eine Vereinfachung. Korrekter:
Checked Exceptions
Unchecked Exceptions
Was sind sie?
Exceptions, die nicht von RuntimeException oder Error erben und vom Compiler behandelt oder deklariert werden müssen.
Programmierfehler oder bewusst definierte Ausnahmen (z. B. eigene RuntimeException-Unterklassen).
Muss man sie behandeln?
Ja (try-catch oder throws)
Nein — aber: du kannst trotzdem fangen!
💡 Beispiel: Eine selbst definierte RuntimeException("Ungültige ID") ist technisch eine Unchecked Exception, wird aber bewusst vom Programmierer geworfen — sie ist kein Bug.
3. throw vs. throws
throw
throws
Wo?
Im Code (innerhalb der Methode)
Im Methodenkopf (Signatur)
Was?
Wirft ein Exception-Objekt jetzt
Kündigt an, dass Exceptions geworfen werden können
Enthält abstrakte Methoden (ohne Körper), die Unterklassen implementieren müssen
Hat auch normale Attribute und Methoden
Darf konkrete und abstrakte Methoden mischen
abstract class Form { protected String name; public abstract double flaeche(); // muss überschrieben werden public void ausgeben() { // kann auch normale Methoden haben System.out.println(name + ": " + flaeche()); }}
Interface (interface)
Alle Attribute sind automatisch public static final (Konstanten)
default-Methoden: können Implementierung haben, aber müssen nicht überschrieben werden
static-Methoden: gehören zur Schnittstelle selbst, nicht zu Instanzen
private-Hilfsmethoden: ab Java 9 möglich! Dienen nur der internen Umsetzung von default-Methoden
Wichtige Regeln (ergänzt)
Regel
Erklärung
Mehrfachvererbung bei Interfaces
Eine Klasse kann mehrere Interfaces implements: class C implements A, B {}
Interface-Hierarchie
Ein Interface kann ein anderes Interface extends: interface X extends Y {}
Abstrakte Methoden
Interfaces definieren Methoden ohnedefault → alle Implementierungen müssen sie überschreiben
5. Exception Chaining – Die Chain durchlaufen
Grundprinzip
Exceptions können verschachtelt werden — eine Exception “umhüllt” eine andere.
throw new Exception("Fehler beim Lesen", e); // ← Chain!// Parameter 1 = neue Nachricht | Parameter 2 = die umhüllte Exception (Cause)
Navigation durch die Chain
Methode
Gibt zurück
e.getMessage()
Nur die Message dieser Ebene
e.getCause()
Die direkt umhüllte Exception (nächste Ebene in der Chain)
e.getCause().getMessage()
Message der direkt darunterliegenden Ebene
⚠️ Korrektur: getCause() gibt immer nur die direkte Ursache zurück
“Die nächste Ebene finden” ❌ getCause() gibt immer die unmittelbar umhüllte Exception zurück. Diese kann wiederum eine eigene Cause haben — man muss also rekursiv/traversieren, nicht einfach “die nächste”.
Beispiel: 3 Layer
// Layer 0: "test.txt (No such file or directory)"// Layer 1: "Fehler beim Lesen"// Layer 2: "Fehler in main()"System.out.println(e.getMessage()); // "Fehler in main()"System.out.println(e.getCause().getMessage()); // "Fehler beim Lesen"System.out.println(e.getCause().getCause().getMessage()); // "test.txt (No such file or directory)"
⚠️ NullPointerException!
Wenn getCause()nichts mehr findet, gibt es null zurück:
e2.getCause().getCause(); // Gibt null zurück — kein Crash hier!// Aber:e2.getCause().getCause().getMessage(); // 💥 NPE! .getMessage() auf null → NullPointerException
6. try-with-resources (AutoCloseable)
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) { String line = br.readLine();} catch (IOException e) { System.out.println(e.getMessage()); // "test.txt (No such file or directory)"}
BufferedReader implementiert AutoCloseable → wird automatisch geschlossen.
Kein manuelles br.close() nötig.
Ressourcen werden auch bei Exception sicher geschlossen.
Mehrere Ressourcen: durch Komma getrennt — sie werden in umgekehrter Reihenfolge geschlossen (LIFO).
7. Best Practices
Regel
Warum?
try-with-resources statt manuell closeen
Verhindert Resource Leaks
Spezifische Exceptions fangen (IOException)
Nicht alles mit Exception abfangen!
Bei neuem Wrappen: Message + Cause angeben
Behält die ursprüngliche Info
getCause() prüfen bevor weiter
Vermeidet NPE
Unchecked Exceptions bewusst setzen
Nicht jede Ausnahme ist ein Bug — man kann auch eigene RuntimeException-Unterklassen definieren
8. Visualisierung der Chain
e ───────────────────── "Fehler in main()" ← Layer 2 (oben)
│
└── getCause() ────── "Fehler beim Lesen" ← Layer 1
│
└── getCause() ─ "test.txt (No such file or directory)" ← Layer 0 (unten, original)
│
└── getCause() → null (kein Crash!)
.getMessage() auf null → 💥 NPE!
9. Quick-Check-Fragen
Was gibt e.getMessage() zurück? → Nur die Message der aktuellen Ebene.
Was gibt e.getCause().getMessage() zurück? → Die Message der direkt darunterliegenden Ebene.
Was passiert, wenn es keine nächste Ebene gibt? → getCause() = null (kein Crash!) → .getMessage() auf null → NPE!
10. Code-Beispiel: Sicheres Durchlaufen der Chain (rekursiv)
public static void printCauseChain(Exception e, int level) { if (e == null) return; // Abbruchbedingung System.out.println("Layer " + level + ": " + e.getMessage()); printCauseChain(e.getCause(), level + 1); // Rekursiver Aufruf}// Ausgabe:// Layer 0: Fehler in main()// Layer 1: Fehler beim Lesen// Layer 2: test.txt (No such file or directory)
11. Verständnisaufgaben & Codeanalyse
Aufgabe A: Polymorphie verstehen
class Tier { String laut() { return "???"; } }class Hund extends Tier { @Override String laut() { return "Wuff!"; } }class Katze extends Tier { @Override String laut() { return "Miau!"; } }Tier t = new Hund();System.out.println(t.laut()); // Was kommt raus? Warum?
Aufgabe B: Checked Exceptions weitergeben
Was passiert, wenn eine Methode eine Checked Exception weiterwirft, ohne sie mit throws zu deklarieren oder intern abzufangen?
Aufgabe C: Mehrere Interfaces — Konflikt auflösen
interface A { default void hi() { System.out.println("A"); } }interface B { default void hi() { System.out.println("B"); } }class C implements A, B {} // Was passiert hier?
Lösung: Eine Klasse muss den Konflikt zwischen zwei default-Methoden explizit auflösen:
class C implements A, B { @Override public void hi() { A.super.hi(); // Oder: B.super.hi(); — du entscheidest! }}
Aufgabe D: Exception Chain implementieren
Schreibe eine Methode String getFullChain(Exception e), die alle Messages der Chain mit Pfeilen verbindet: "Fehler1 → Fehler2 → Original".
12. Zusammenfassung der wichtigsten Korrekturen
Thema
Alt (❌)
Neu (✅)
Checked/Unchecked
”Checked = von außen, Unchecked = im Code"
"Müssen behandelt werden / müssen nicht” — Unchecked kann auch bewusst sein
Dynamisch (Override) vs. Statisch (Overload) klar getrennt
NPE bei Chain
”getCause() → null → CRASH!"
"getCause() gibt null (kein Crash!) — .getMessage() auf null → 💥 NPE”
Erstellt aus einer Lernsession über Polymorphie, Exceptions und Exception Chaining. Verbessert nach Review: 9/10 → fachliche Korrekturen + Verständnisaufgaben ergänzt.