Von Nova Trent, Junior Entwicklerin bei Java Fleet Systems Consulting
Schwierigkeit: 🟢 Einsteiger
Lesezeit: 35–40 Minuten
Voraussetzungen: Tag 1–6 abgeschlossen
📋 Kursübersicht: Java OOP in 10 Tagen
| Tag | Thema | Status |
|---|---|---|
| 1 | OOP-Konzepte & erste Klasse | ✅ Abgeschlossen |
| 2 | Attribute & Methoden | ✅ Abgeschlossen |
| 3 | Datenkapselung & Sichtbarkeit | ✅ Abgeschlossen |
| 4 | Konstruktoren | ✅ Abgeschlossen |
| 5 | Konstanten & Static | ✅ Abgeschlossen 🔴 |
| 6 | Vererbung – Grundlagen | ✅ Abgeschlossen |
| → 7 | Polymorphie & Abstrakte Klassen | 📍 Du bist hier |
| 8 | Typumwandlung & instanceof | ⏳ |
| 9 | Interfaces & Enumerationen | ⏳ |
| 10 | Ausnahmebehandlung | 🔴 KOPFNUSS |
Voraussetzung: Tag 1–6 abgeschlossen
🔄 Kurz-Wiederholung: Challenge von Tag 6
Die Aufgabe war: Erstelle eine Motorrad-Klasse, die von Fahrzeug erbt.
Lösung:
public class Motorrad extends Fahrzeug {
private int hubraum;
private String typ; // Chopper, Sportler, etc.
public Motorrad(String marke, int baujahr, int hubraum, String typ) {
super(marke, baujahr); // Eltern-Konstruktor
this.hubraum = hubraum;
this.typ = typ;
}
@Override
public void fahren(int km) {
super.fahren(km);
System.out.println("🏍️ Motorrad kurvt " + km + " km!");
}
public void wheelie() {
System.out.println("🏍️ " + marke + " macht einen Wheelie!");
}
public int getHubraum() { return hubraum; }
public String getTyp() { return typ; }
}
Hast du’s? Heute wird’s richtig spannend — Polymorphie!
⚡ Das Wichtigste in 30 Sekunden
Das Problem: Du hast verschiedene Fahrzeuge (Auto, Motorrad, LKW). Du willst sie alle gleich behandeln, aber jedes soll sich anders verhalten.
Die Lösung: Polymorphie! Eine Eltern-Variable kann verschiedene Kind-Objekte halten, und jedes verhält sich seiner Art entsprechend.
Heute lernst du:
- ✅ Polymorphie — „Vielgestaltigkeit“
- ✅ Methoden überschreiben mit
@Override - ✅ Abstrakte Klassen — Templates für Kindklassen
- ✅ Abstrakte Methoden — „Muss implementiert werden!“
Zeit-Investment: 35–40 Minuten
👋 Nova: „Das war mein Aha-Moment!“
Hey! 👋
Nova hier.
Real talk: Als ich Polymorphie verstanden habe, hat OOP endlich klick gemacht. Vorher dachte ich: „Warum so kompliziert? Ich kann doch einfach verschiedene Variablen nutzen.“
Aber stell dir vor: Du hast eine Liste mit 1000 Fahrzeugen — Autos, Motorräder, LKWs, alles durcheinander. Mit Polymorphie kannst du fahrzeug.fahren() aufrufen und jedes Fahrzeug macht automatisch das Richtige.
Das ist die Magie! 🚀
🟢 GRUNDLAGEN
Was ist Polymorphie?
„Polymorphie“ kommt aus dem Griechischen:
- poly = viele
- morph = Form/Gestalt
Eine Variable, viele Formen. Eine Fahrzeug-Variable kann ein Auto, ein Motorrad oder einen LKW halten — und jedes verhält sich anders.
Fahrzeug f;
f = new Auto("VW", 2024, 4);
f.fahren(10); // "Auto fährt auf der Straße"
f = new Motorrad("Harley", 2023, 1200, "Chopper");
f.fahren(10); // "Motorrad kurvt"
f = new LKW("MAN", 2022, 20000);
f.fahren(10); // "LKW rollt schwer"

Abbildung 1: Eine Variable vom Eltern-Typ kann verschiedene Kind-Objekte halten.
Methoden überschreiben
Kindklassen können Methoden der Elternklasse überschreiben (override):
// Elternklasse
public class Fahrzeug {
protected String marke;
protected int kilometerstand;
public void fahren(int km) {
kilometerstand += km;
System.out.println("Fahrzeug fährt " + km + " km.");
}
}
// Kindklasse
public class Auto extends Fahrzeug {
private int anzahlTueren;
@Override // Wichtig!
public void fahren(int km) {
kilometerstand += km;
System.out.println("🚗 Auto fährt " + km + " km auf der Straße.");
}
}
Die @Override-Annotation
@Override ist dein Sicherheitsnetz:

Abbildung 2: @Override schützt vor Tippfehlern — der Compiler prüft, ob du wirklich überschreibst.
// OHNE @Override — gefährlich!
public void faren(int km) { // Tippfehler! Neue Methode statt Override!
// ...
}
// MIT @Override — sicher!
@Override
public void faren(int km) { // ❌ Compilerfehler: überschreibt nichts!
// ...
}
Regel: IMMER @Override verwenden!
Polymorphie in Aktion
Der wahre Power-Move — eine Liste mit verschiedenen Objekten:
List<Fahrzeug> fuhrpark = new ArrayList<>();
fuhrpark.add(new Auto("VW Golf", 2024, 4));
fuhrpark.add(new Motorrad("Harley", 2023, 1200, "Chopper"));
fuhrpark.add(new Auto("BMW X5", 2022, 5));
fuhrpark.add(new LKW("MAN", 2021, 15000));
// Alle fahren — jeder auf seine Art!
for (Fahrzeug f : fuhrpark) {
f.fahren(100); // Polymorphie!
}
Output:
🚗 Auto fährt 100 km auf der Straße. 🏍️ Motorrad kurvt 100 km. 🚗 Auto fährt 100 km auf der Straße. 🚛 LKW rollt 100 km schwer.
super.methode() — Eltern-Methode aufrufen
Manchmal willst du die Eltern-Methode ERWEITERN, nicht ersetzen:
@Override
public void fahren(int km) {
super.fahren(km); // Erst Eltern-Code ausführen
System.out.println("🚗 ...mit Klimaanlage!"); // Dann erweitern
}
🟢 Abstrakte Klassen
Das Problem
Was ist ein „Fahrzeug“ eigentlich? Kannst du ein „Fahrzeug“ fahren? Nein — du fährst ein Auto oder ein Motorrad.
Fahrzeug ist nur ein Konzept, keine echte Sache. Es sollte nicht instanziierbar sein!
Die Lösung: abstract
public abstract class Fahrzeug {
protected String marke;
protected int baujahr;
public Fahrzeug(String marke, int baujahr) {
this.marke = marke;
this.baujahr = baujahr;
}
// Normale Methode — hat Implementierung
public void info() {
System.out.println(marke + " (" + baujahr + ")");
}
// Abstrakte Methode — KEINE Implementierung!
public abstract void fahren(int km);
}

Abbildung 3: Abstrakte Klassen können nicht instanziiert werden — nur ihre Kindklassen.
Regeln für abstrakte Klassen
- Können nicht instanziiert werden:
new Fahrzeug(...); // ❌ Compilerfehler! new Auto(...); // ✅ OK - Können abstrakte Methoden haben:
public abstract void fahren(int km); // Kein Body! - Kindklassen MÜSSEN abstrakte Methoden implementieren:
public class Auto extends Fahrzeug { @Override public void fahren(int km) { // MUSS implementiert werden! } } - Können normale Methoden haben:
public void info() { // Normale Methode mit Body System.out.println(marke); }
Abstrakte Methoden
Eine abstrakte Methode ist wie ein Vertrag: „Jede Kindklasse MUSS das implementieren!“
public abstract class Tier {
protected String name;
public Tier(String name) {
this.name = name;
}
// Jedes Tier macht Geräusche — aber unterschiedlich!
public abstract void lautGeben();
}
public class Hund extends Tier {
public Hund(String name) {
super(name);
}
@Override
public void lautGeben() {
System.out.println("🐕 " + name + ": Wuff!");
}
}
public class Katze extends Tier {
public Katze(String name) {
super(name);
}
@Override
public void lautGeben() {
System.out.println("🐈 " + name + ": Miau!");
}
}
Wann abstrakte Klasse?
| Situation | Lösung |
|---|---|
| Gemeinsamer Code für Kindklassen | Abstrakte Klasse |
| Nur Methodensignaturen vorgeben | Interface (Tag 9) |
| Instanziierung verhindern | abstract |
| „Ist-ein“-Beziehung | Vererbung / abstrakte Klasse |
🟡 PROFESSIONALS
Schon OOP-Erfahrung aus C#, C++, PHP? Hier sind die Java-Besonderheiten.
Für C#-Umsteiger
// C#
public abstract class Fahrzeug {
public abstract void Fahren(int km); // PascalCase
public virtual void Info() { } // virtual für Override
}
// Java
public abstract class Fahrzeug {
public abstract void fahren(int km); // camelCase
public void info() { } // Kein virtual nötig
}
In Java sind alle Methoden standardmäßig „virtual“ (überschreibbar). Nur final verhindert Override.
Für C++-Umsteiger
// C++
class Fahrzeug {
public:
virtual void fahren(int km) = 0; // Pure virtual = abstract
virtual void info() { } // Virtual für Override
};
// Java
public abstract class Fahrzeug {
public abstract void fahren(int km); // abstract = pure virtual
public void info() { } // Implizit virtual
}
Für PHP-Umsteiger
// PHP
abstract class Fahrzeug {
abstract public function fahren(int $km): void;
public function info(): void { }
}
// Java
public abstract class Fahrzeug {
public abstract void fahren(int km);
public void info() { }
}
Fast identisch! PHP hat sich von Java inspirieren lassen.
🔵 BONUS
Für Wissbegierige: Template Method Pattern, sealed classes.
Template Method Pattern
Abstrakte Klassen sind perfekt für das Template Method Pattern:
public abstract class Bericht {
// Template Method — definiert den Ablauf
public final void generieren() {
oeffnen();
schreibeInhalt(); // Abstract — Kindklasse bestimmt
schliessen();
}
private void oeffnen() {
System.out.println("Bericht wird geöffnet...");
}
// Abstrakt — muss implementiert werden
protected abstract void schreibeInhalt();
private void schliessen() {
System.out.println("Bericht wird geschlossen.");
}
}
public class PDFBericht extends Bericht {
@Override
protected void schreibeInhalt() {
System.out.println("Schreibe PDF-Inhalt...");
}
}
public class HTMLBericht extends Bericht {
@Override
protected void schreibeInhalt() {
System.out.println("Schreibe HTML-Inhalt...");
}
}
Sealed Classes (Java 17+)
Mit sealed kannst du einschränken, welche Klassen erben dürfen:
public sealed class Fahrzeug permits Auto, Motorrad, LKW {
// ...
}
public final class Auto extends Fahrzeug { }
public final class Motorrad extends Fahrzeug { }
public final class LKW extends Fahrzeug { }
// public class Fahrrad extends Fahrzeug { } // ❌ Nicht erlaubt!
💬 Real Talk
Tom fragt, Nova erklärt — Die Fragen, die sich jeder stellt.
Java Fleet Kaffeeküche, 15:00 Uhr.
Tom: Nova, ich versteh nicht, warum ich @Override brauche. Die Methode wird doch trotzdem überschrieben?
Nova: Stimmt! Aber stell dir vor, du tippst dich. Ohne @Override erstellt Java einfach eine NEUE Methode. Mit @Override sagt der Compiler: „Hey, du wolltest überschreiben, aber die Methode gibt’s nicht!“
Tom: Okay, macht Sinn. Und abstrakte Klassen? Warum nicht einfach normale Klassen?
Nova: Weil du manchmal verhindern willst, dass jemand new Fahrzeug() macht. Was IST ein Fahrzeug? Es ist nur ein Konzept! Du kannst nur konkrete Dinge wie Auto oder Motorrad fahren.
Tom: Aber ich kann doch einfach den Konstruktor private machen?
Nova: Könntest du. Aber dann könnten Kindklassen nicht mehr super() aufrufen. Abstrakt ist sauberer und sagt klar: „Das ist ein Template, keine echte Klasse.“
Tom: Wann brauche ich Polymorphie in der Praxis?
Nova: Ständig! Denk an eine GUI: Du hast Buttons, Textfelder, Labels — alle erben von UIElement. Du kannst alle in einer Liste speichern und element.render() aufrufen. Jedes Element zeichnet sich selbst.
✅ Checkpoint: Hast du es verstanden?
Quiz
Frage 1: Was bedeutet „Polymorphie“?
Frage 2: Was passiert ohne @Override, wenn du einen Tippfehler im Methodennamen hast?
Frage 3: Kann eine abstrakte Klasse einen Konstruktor haben?
Frage 4: Dieser Code:
abstract class A {
public abstract void foo();
public abstract void bar();
}
class B extends A {
@Override
public void foo() { }
}
Kompiliert das? Warum (nicht)?
Frage 5: Was ist der Unterschied zwischen einer abstrakten Methode und einer normalen Methode?
Mini-Challenge
Aufgabe: Erstelle eine Mitarbeiter-Hierarchie:
- Abstrakte Klasse
Mitarbeiter:- Attribute:
name,personalnummer,gehalt - Normale Methode:
arbeiten()— „Name arbeitet.“ - Normale Methode:
getJahresgehalt()— gehalt * 12 - Abstrakte Methode:
getRolle()— gibt Rolle als String zurück
- Attribute:
- Kindklasse
Entwickler:- Zusätzliches Attribut:
programmiersprache arbeiten()überschreiben: „Name programmiert in Sprache.“getRolle()implementieren: „Entwickler“
- Zusätzliches Attribut:
- Kindklasse
Manager:- Zusätzliches Attribut:
teamgroesse getJahresgehalt()überschreiben: +10% BonusgetRolle()implementieren: „Manager“
- Zusätzliches Attribut:
Lösung: Findest du am Anfang von Tag 8! 🚀
❓ FAQ — Häufig gestellte Fragen
Frage 1: Kann eine abstrakte Klasse Attribute haben?
Ja! Abstrakte Klassen können alles haben, was normale Klassen haben — plus abstrakte Methoden.
Frage 2: Muss eine abstrakte Klasse abstrakte Methoden haben?
Nein! Eine Klasse kann abstract sein, nur um Instanziierung zu verhindern, ohne abstrakte Methoden.
Frage 3: Kann eine Kindklasse auch abstrakt sein?
Ja! Dann muss SIE die abstrakten Methoden nicht implementieren — aber ihre Kindklassen müssen es dann tun.
Frage 4: Was ist der Unterschied zu Interfaces?
Abstrakte Klassen können Attribute und Konstruktoren haben. Interfaces (Tag 9) sind „reiner“ — nur Methodensignaturen. Außerdem: Eine Klasse kann nur EINE Elternklasse haben, aber MEHRERE Interfaces implementieren.
Frage 5: Wann @Override, wann nicht?
IMMER @Override verwenden, wenn du überschreibst! Es gibt keinen Grund, es wegzulassen.
Frage 6: Kann ich super.methode() in einer abstrakten Methode aufrufen?
Nein — abstrakte Methoden haben keinen Body. Aber in überschriebenen NORMALEN Methoden kannst du super.methode() aufrufen.
Frage 7: Bernd meinte, Vererbung sei „überbewertet“. Was meint er?
seufzt Typisch Bernd. Er hat einen Punkt: Zu tiefe Vererbungshierarchien werden unübersichtlich. „Composition over Inheritance“ ist oft besser — statt Auto extends Fahrzeug extends Maschine extends Ding lieber separate Komponenten.
Aber für klare IS-A-Beziehungen (Auto IST EIN Fahrzeug) ist Vererbung perfekt. Wie immer: Balance! 🤷
📚 Quiz-Lösungen
Frage 1: Was bedeutet „Polymorphie“?
Antwort:
„Vielgestaltigkeit“ — eine Variable kann Objekte verschiedener Klassen halten, und jedes Objekt verhält sich seiner Klasse entsprechend.
Fahrzeug f = new Auto(); // f.fahren() → Auto-Verhalten f = new Motorrad(); // f.fahren() → Motorrad-Verhalten
Frage 2: Was passiert ohne @Override bei Tippfehler?
Antwort:
Java erstellt eine neue Methode statt zu überschreiben! Der Code kompiliert, aber die Eltern-Methode wird aufgerufen statt deiner. Bug bleibt unentdeckt!
Frage 3: Kann abstrakte Klasse Konstruktor haben?
Antwort:
Ja! Der Konstruktor wird von Kindklassen mit super(...) aufgerufen. Die abstrakte Klasse selbst kann trotzdem nicht instanziiert werden.
Frage 4: Kompiliert das?
class B extends A {
@Override
public void foo() { }
}
Antwort:
Nein! B implementiert nur foo(), aber nicht bar(). Entweder bar() auch implementieren, oder B selbst abstract machen.
Frage 5: Abstrakte vs. normale Methode?
Antwort:
- Normale Methode: Hat einen Body (Implementierung)
- Abstrakte Methode: Hat KEINEN Body, nur Signatur. Kindklassen MÜSSEN sie implementieren.
public void normal() { /* Body */ }
public abstract void abstrakt(); // Kein Body!
🎉 Tag 7 geschafft!
Stark! 🚀
Das hast du heute gelernt:
- ✅ Polymorphie — eine Variable, viele Formen
- ✅
@Override— dein Sicherheitsnetz - ✅ Abstrakte Klassen — Templates für Kindklassen
- ✅ Abstrakte Methoden — „Muss implementiert werden!“
Mehr als die Hälfte geschafft! 💪
🔮 Wie geht’s weiter?
Morgen in Tag 8: Typumwandlung & instanceof
Du lernst:
- Upcast und Downcast
instanceof— Typ zur Laufzeit prüfen- Pattern Matching (Java 16+)
- Sichere Typkonvertierung
Das wird praktisch! 🎯
📦 Downloads
Starter-Projekt für Tag 7:
⬇️ Tag07_Polymorphie.zip — Komplettes Maven-Projekt
Inhalt:
Tag07_Polymorphie/
├── pom.xml
├── README.md
└── src/main/java/
└── de/javafleet/oop/
├── Main.java
└── model/
├── Fahrzeug.java (abstract)
├── Auto.java
├── Motorrad.java (Lösung Tag 6)
└── LKW.java
Grafiken:
- ⬇️ polymorphie-konzept.svg — Polymorphie visualisiert
- ⬇️ abstrakte-klasse.svg — Abstrakte Klasse erklärt
- ⬇️ override-annotation.svg — @Override Sicherheit
🔧 Troubleshooting
Problem: „cannot instantiate abstract class“
error: Fahrzeug is abstract; cannot be instantiated
Lösung: Abstrakte Klassen können nicht mit new erstellt werden! Erstelle eine konkrete Kindklasse.
Problem: „must implement abstract method“
error: Auto is not abstract and does not override abstract method fahren()
Lösung: Deine Kindklasse muss ALLE abstrakten Methoden der Elternklasse implementieren!
Problem: „method does not override“
error: method does not override or implement a method from a supertype
Lösung: Tippfehler im Methodennamen oder falsche Signatur. Prüfe Elternklasse!
🔗 Resources & Links
🟢 Für Einsteiger
| Ressource | Beschreibung | Sprache |
|---|---|---|
| Oracle — Polymorphism | Offizielle Doku | 🇬🇧 |
| Oracle — Abstract Classes | Offizielle Doku | 🇬🇧 |
🟡 Für Fortgeschrittene
| Ressource | Beschreibung | Sprache |
|---|---|---|
| Effective Java — Item 20 | Abstract Classes vs Interfaces | 🇬🇧 |
👋 Bis morgen!
Tag 7 ist geschafft. Polymorphie und abstrakte Klassen sind jetzt dein Werkzeug!
Morgen: Typumwandlung & instanceof — damit du Objekte zur Laufzeit prüfen kannst.
See you! 🚀
Nova Trent
Junior Entwicklerin bei Java Fleet Systems Consulting
„Polymorphie ist, wenn du sagst ‚fahr!‘ und jedes Fahrzeug weiß, wie.“ 🎯
Praxis-Challenge
🎯 Zahlungssystem
Schwierigkeit: 🟢 Einsteiger
Geschätzte Zeit: 60–75 Minuten
Voraussetzungen: Tag 1–7 abgeschlossen
Szenario
Du entwickelst ein Zahlungssystem für einen Online-Shop. Kunden können mit verschiedenen Methoden bezahlen: Kreditkarte, PayPal, Überweisung oder Rechnung. Alle Zahlungsarten teilen gemeinsame Eigenschaften, haben aber unterschiedliche Verarbeitungslogik.
Das ist der perfekte Fall für abstrakte Klassen und Polymorphie!
Deine Aufgaben
1. Abstrakte Basisklasse Zahlung
Eine Zahlung kann nie „einfach so“ existieren — sie ist immer eine konkrete Zahlungsart. Daher: abstract!
| Element | Details |
|---|---|
| Attribute | betrag (double), zeitstempel (LocalDateTime), status (String) |
| Sichtbarkeit | Attribute protected |
| Konstruktor | Parameter: betrag. Zeitstempel = LocalDateTime.now(), Status = "OFFEN" |
| Abstrakte Methode | boolean ausfuehren() — jede Zahlungsart implementiert das anders |
| Abstrakte Methode | String getZahlungsart() — gibt den Namen der Zahlungsart zurück |
| Konkrete Methode | void stornieren() — setzt Status auf "STORNIERT", gibt Meldung aus |
| Konkrete Methode | String getQuittung() — gibt formatierte Quittung zurück |
| Getter | Für alle Attribute |
Hinweis zur Quittung:
--- QUITTUNG --- Zahlungsart: [getZahlungsart()] Betrag: [betrag] EUR Status: [status] Datum: [zeitstempel formatiert] ----------------
2. Konkrete Klasse Kreditkartenzahlung extends Zahlung
| Element | Details |
|---|---|
| Zusätzliche Attribute | kartennummer (String, letzte 4 Ziffern), karteninhaber (String) |
| Konstruktor | Parameter: betrag, kartennummer, karteninhaber |
| ausfuehren() | Simuliert Zahlung: gibt true zurück wenn Betrag ≤ 5000, sonst false. Setzt Status entsprechend auf "BEZAHLT" oder "ABGELEHNT" |
| getZahlungsart() | Gibt "Kreditkarte (****XXXX)" zurück (XXXX = letzte 4 Ziffern) |
3. Konkrete Klasse PayPalZahlung extends Zahlung
| Element | Details |
|---|---|
| Zusätzliche Attribute | email (String) |
| Konstruktor | Parameter: betrag, email |
| ausfuehren() | Prüft ob Email „@“ enthält. Wenn ja: Status = "BEZAHLT", return true. Sonst: Status = "FEHLGESCHLAGEN", return false |
| getZahlungsart() | Gibt "PayPal (email)" zurück |
4. Konkrete Klasse Ueberweisung extends Zahlung
| Element | Details |
|---|---|
| Zusätzliche Attribute | iban (String), verwendungszweck (String) |
| Konstruktor | Parameter: betrag, iban, verwendungszweck |
| ausfuehren() | Überweisungen sind immer „pending“: Status = "WARTEND", return true |
| getZahlungsart() | Gibt "Überweisung (IBAN: XXXX...)" zurück (erste 4 Zeichen der IBAN) |
| Überschreibt | stornieren() — ruft super.stornieren() auf, gibt zusätzlich „Rückbuchung wird eingeleitet…“ aus |
5. Konkrete Klasse RechnungsKauf extends Zahlung
| Element | Details |
|---|---|
| Zusätzliche Attribute | rechnungsadresse (String), zahlungsziel (int, Tage) |
| Konstruktor | Parameter: betrag, rechnungsadresse, zahlungsziel |
| ausfuehren() | Rechnungskauf nur bis 1000 EUR erlaubt. Wenn Betrag ≤ 1000: Status = "RECHNUNG_VERSENDET", return true. Sonst: Status = "ABGELEHNT", return false |
| getZahlungsart() | Gibt "Rechnung (Zahlungsziel: XX Tage)" zurück |
| Neue Methode | LocalDateTime getFaelligkeit() — gibt zeitstempel.plusDays(zahlungsziel) zurück |
6. Verwaltungsklasse ZahlungsManager
Diese Klasse zeigt Polymorphie in Aktion!
public class ZahlungsManager {
private List<Zahlung> zahlungen = new ArrayList<>();
// Zahlung hinzufügen und sofort ausführen
public boolean verarbeite(Zahlung zahlung) { ... }
// Alle Zahlungen eines bestimmten Status finden
public List<Zahlung> findeNachStatus(String status) { ... }
// Gesamtsumme aller erfolgreichen Zahlungen
public double getGesamtUmsatz() { ... }
// Alle Quittungen ausgeben
public void druckeAlleQuittungen() { ... }
}
Hinweise zur Implementierung:
verarbeite(Zahlung zahlung):
- Fügt die Zahlung zur Liste hinzu
- Ruft
zahlung.ausfuehren()auf (Polymorphie!) - Gibt das Ergebnis zurück
getGesamtUmsatz():
- Summiert nur Zahlungen mit Status
"BEZAHLT"oder"RECHNUNG_VERSENDET"
Test-Code für Main
public class Main {
public static void main(String[] args) {
ZahlungsManager manager = new ZahlungsManager();
// Verschiedene Zahlungsarten erstellen
Zahlung kreditkarte = new Kreditkartenzahlung(149.99, "1234", "Max Mustermann");
Zahlung paypal = new PayPalZahlung(59.90, "max@example.com");
Zahlung ueberweisung = new Ueberweisung(1250.00, "DE89370400440532013000", "Bestellung #12345");
Zahlung rechnung = new RechnungsKauf(89.00, "Musterstr. 1, 12345 Berlin", 14);
// Zu hohe Kreditkartenzahlung (wird abgelehnt)
Zahlung zuHoch = new Kreditkartenzahlung(7500.00, "5678", "Erika Musterfrau");
// Ungültige PayPal-Email
Zahlung ungueltig = new PayPalZahlung(29.99, "keine-email");
// Alle verarbeiten - Polymorphie in Aktion!
System.out.println("=== Zahlungen verarbeiten ===");
System.out.println("Kreditkarte: " + manager.verarbeite(kreditkarte));
System.out.println("PayPal: " + manager.verarbeite(paypal));
System.out.println("Überweisung: " + manager.verarbeite(ueberweisung));
System.out.println("Rechnung: " + manager.verarbeite(rechnung));
System.out.println("Zu hoch: " + manager.verarbeite(zuHoch));
System.out.println("Ungültig: " + manager.verarbeite(ungueltig));
// Gesamtumsatz
System.out.println("\n=== Statistik ===");
System.out.println("Gesamtumsatz: " + manager.getGesamtUmsatz() + " EUR");
// Erfolgreiche Zahlungen
System.out.println("\n=== Erfolgreiche Zahlungen ===");
for (Zahlung z : manager.findeNachStatus("BEZAHLT")) {
System.out.println("- " + z.getZahlungsart() + ": " + z.getBetrag() + " EUR");
}
// Eine Quittung ausgeben
System.out.println("\n=== Beispiel-Quittung ===");
System.out.println(kreditkarte.getQuittung());
// Stornierung testen
System.out.println("=== Stornierung ===");
ueberweisung.stornieren(); // Soll zusätzliche Meldung ausgeben!
System.out.println("Status nach Storno: " + ueberweisung.getStatus());
// Fälligkeit bei Rechnung
System.out.println("\n=== Rechnungsdetails ===");
RechnungsKauf rk = (RechnungsKauf) rechnung; // Cast nötig für spezielle Methode
System.out.println("Fällig am: " + rk.getFaelligkeit());
}
}
Erwartete Ausgabe (ungefähr)
=== Zahlungen verarbeiten === Kreditkarte: true PayPal: true Überweisung: true Rechnung: true Zu hoch: false Ungültig: false === Statistik === Gesamtumsatz: 298.89 EUR === Erfolgreiche Zahlungen === - Kreditkarte (****1234): 149.99 EUR - PayPal (max@example.com): 59.9 EUR === Beispiel-Quittung === --- QUITTUNG --- Zahlungsart: Kreditkarte (****1234) Betrag: 149.99 EUR Status: BEZAHLT Datum: 2025-01-06 14:30 ---------------- === Stornierung === Zahlung wurde storniert. Rückbuchung wird eingeleitet... Status nach Storno: STORNIERT === Rechnungsdetails === Fällig am: 2025-01-20T14:30:00
Checkliste: Das wird getestet
Abstrakte Klassen
- [ ]
Zahlungistabstractdeklariert - [ ]
ausfuehren()undgetZahlungsart()sindabstract - [ ]
stornieren()undgetQuittung()sind konkret implementiert - [ ] Man kann kein
new Zahlung(...)erstellen
Polymorphie
- [ ]
List<Zahlung>enthält verschiedene konkrete Typen - [ ]
zahlung.ausfuehren()ruft die richtige Implementierung auf - [ ]
zahlung.getZahlungsart()gibt den korrekten Typ zurück
Methoden-Überschreibung
- [ ] Alle konkreten Klassen implementieren die abstrakten Methoden
- [ ]
Ueberweisung.stornieren()erweitert mitsuper.stornieren() - [ ]
@OverrideAnnotation bei allen überschriebenen Methoden
Vererbung (Wiederholung Tag 6)
- [ ]
extends Zahlungbei allen konkreten Klassen - [ ]
super(betrag)im Konstruktor - [ ]
protectedAttribute werden genutzt
Hinweise
abstractKlassen können keine Instanzen haben —new Zahlung(100)gibt Compilerfehler- Abstrakte Methoden haben keinen Body — nur Signatur mit Semikolon
- Konkrete Klassen MÜSSEN alle abstrakten Methoden implementieren — sonst Compilerfehler
- Polymorphie: Die Variable ist vom Typ
Zahlung, das Objekt ist z.B.Kreditkartenzahlung
Projektstruktur
src/main/java/
└── de/javafleet/oop/
├── Main.java
├── ZahlungsManager.java
└── zahlung/
├── Zahlung.java
├── Kreditkartenzahlung.java
├── PayPalZahlung.java
├── Ueberweisung.java
└── RechnungsKauf.java
Imports nicht vergessen!
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List;
Lösung: Findest du in Tag07_Polymorphie_Loesung.md
© 2025 Java Fleet Systems Consulting
Tags: #Java #OOP #Polymorphie #Abstract #Override #Tutorial
📚 Das könnte dich auch interessieren
© 2025 Java Fleet Systems Consulting | java-developer.online

