Uebungen und Vertiefung
Dieses Kapitel basiert auf dem umfangreichen OOP-Uebungsblatt. Es ist als Trainingssammlung angelegt und verbindet mehrere fortgeschrittene Themen in einem Paket:
- Kovarianz von Arrays
- Polymorphe Zuweisungen
- Casts und Laufzeitfehler
- statische Typisierung im Zusammenspiel mit Vererbung
- Regeln zu
static,protectedund Konstruktoren
Themenfokus des Arbeitsblatts
Das Blatt ist bewusst kein einzelnes Theoriepapier, sondern eine Serie von Pruef- und Begruendungsaufgaben. Ziel ist nicht nur "richtig/ falsch ankreuzen", sondern ein belastbares Modell davon, warum ein Ausdruck in Java erlaubt, verboten oder erst zur Laufzeit problematisch ist.
Array-Kovarianz in Java
Ein Schluesselbeispiel aus dem Blatt:
GeometrischeFigur[] figuren = new Kreis[10];
figuren[5] = new Rechteck(10, 20, 30);
Warum kompiliert das, obwohl es spaeter krachen kann?
Kreis[]ist in Java ein Subtyp vonGeometrischeFigur[](Kovarianz).- Der statische Typ der Referenz erlaubt also die Zuweisung.
- Zur Laufzeit bleibt das echte Array aber ein
Kreis[]. - Ein
Rechteckpasst dort nicht hinein ->ArrayStoreException.
Das Beispiel zeigt sehr gut die Grenze zwischen Compile-Time-Typpruefung und Laufzeittyp.
Polymorphe Zuweisungen systematisch pruefen
Im Blatt werden Klassen wie Tier, Hund, Pudel, Katze verwendet. Die Kernregel:
- Upcast (Subtyp -> Obertyp) ist ohne Cast erlaubt.
- Downcast (Obertyp -> Subtyp) braucht Cast und kann zur Laufzeit fehlschlagen.
Beispiele:
Tier t1 = new Hund(); // erlaubt
Tier t2 = new Pudel(); // erlaubt
Hund h = new Pudel(); // erlaubt
Katze k = new Tier(); // nicht erlaubt ohne Cast (und fachlich unsicher)
Das Blatt trainiert genau diese Zuordnungspruefung in vielen Varianten.
Statischer Typ vs. dynamischer Typ
Merksatz (zentral fuer das ganze Arbeitsblatt):
- Der statische Typ entscheidet, was der Compiler zulassen darf.
- Der dynamische Typ entscheidet, was zur Laufzeit wirklich passiert.
Das gilt fuer:
- Methodenaufrufaufloesung (Override)
- gueltige Casts
- Laufzeitfehler trotz erfolgreicher Kompilierung
Aufgabenklasse: "Welche Beziehungen muessen zwischen Klassen gelten?"
Das Arbeitsblatt nutzt auch abstrakte Variablenmengen wie O, X, T, M und gibt erlaubte/unerlaubte Zuweisungen vor. Daraus soll ein moegliches Klassendiagramm abgeleitet werden.
Warum ist das wertvoll?
- Man denkt nicht nur in Syntax, sondern in Typgraphen.
- Man trainiert Konsistenzbedingungen von Vererbung.
- Man erkennt schneller, welche Zuweisungen strukturell unmoeglich sind.
Polymorphie plus statische Typisierung im Produktbeispiel
Im Blatt werden Typbeziehungen mit Klassen wie Produkt, LebensmittelProdukt, Steak, Haushaltsgeraet geprueft. Typische Fragen:
- Ist
Produkt p = steak;erlaubt? - Ist
Haushaltsgeraet h = steak;erlaubt? - Ist ein Cast moeglich, kompilierbar, aber zur Laufzeit unsicher?
- Wie verhaelt sich
nullin Typzuweisungen?
Besonders didaktisch stark ist dabei die Kombination aus:
- direkten Zuweisungen
- expliziten Casts
- abstrakten Klassen (z. B. mit abstrakter Steuerberechnung)
Regeln fuer Casts
Kompilierbarkeit
Ein Cast kann kompilieren, wenn aus Sicht des Typbaums eine Umwandlung denkbar ist.
Laufzeitsicherheit
Ob der Cast wirklich funktioniert, haengt vom konkreten Objekt ab.
Produkt p = new Steak(...);
Steak s = (Steak) p; // sicher, wenn p wirklich auf Steak zeigt
Produkt p = new Haushaltsgeraet(...);
Steak s = (Steak) p; // kompiliert evtl., aber Laufzeitfehler
null als Sonderfall
Das Blatt enthaelt auch Aufgaben mit null.
nullkann fast jedem Referenztyp zugewiesen werden.- Daraus folgt nicht, dass ein Methodenaufruf sicher ist.
Beispiel:
LebensmittelProdukt lmp = null;
Produkt p = lmp; // erlaubt
p.toString(); // NullPointerException
Kurzer Block zu static und Vererbung
Das Uebungsblatt prueft auch begriffliche Aussagen, z. B.:
- Zugriff von nicht-statischen Methoden auf statische Variablen
- Sichtbarkeit von
protected - Konstruktoren und Vererbung
Wichtig fuer die Einordnung:
- Konstruktoren werden nicht vererbt.
static-Member gehoeren zur Klasse, nicht zum Objekt.protectedsichert Erweiterbarkeit in Subklassen.
Loesestrategie fuer Zuweisungsaufgaben
- Vererbungsbaum skizzieren.
- Fuer jede Variable den statischen Typ notieren.
- Rechte Seite auf konkreten Objekttyp pruefen.
- Upcast/Downcast unterscheiden.
- Bei Casts separate Laufzeitpruefung notieren.
Diese Methode reduziert Fehler deutlich.
Typische Fehlannahmen
- "Wenn es kompiliert, ist es sicher" Falsch: Laufzeittypen koennen Casts oder Array-Zuweisungen brechen.
- "
==prueft inhaltliche Gleichheit" Bei Objekten und Arrays vergleicht==Referenzen. - "Ein Cast macht ungueltige Objekte gueltig" Ein Cast aendert nicht den realen Objekttyp.
- "
nullhat keinen Typ"nullist typkompatibel mit Referenztypen, bleibt aber nicht aufrufbar.
Vertiefungsaufgaben
- Baue eine kleine Tierhierarchie und pruefe 15 verschiedene Zuweisungen.
- Erstelle gezielt zwei Casts, die kompilieren, aber zur Laufzeit scheitern.
- Reproduziere eine
ArrayStoreExceptionmit einer kovarianten Arrayzuweisung. - Erstelle dieselbe Aufgabe mit
List<T>und vergleiche, warum Generics hier strenger sind. - Formuliere fuer jede Aufgabe den statischen und dynamischen Typ explizit.
Zusammenfassung
Das OOP-Uebungsblatt trainiert den Uebergang von "Java schreiben" zu "Java begruenden":
- Typbeziehungen verstehen statt nur auswendig lernen
- Compile-Time- und Runtime-Sicht sauber trennen
- Zuweisungen, Casts und Polymorphie mit System pruefen
Damit wird die Grundlage gelegt, um spaetere Framework- oder API-Codebasen sicher zu lesen und zu erweitern.
Systematik fuer Zuweisungsfragen
Das Arbeitsblatt enthaelt viele Aussagen der Form "Moeglich / Nicht moeglich". Eine zuverlaessige Loesestrategie besteht aus drei Ebenen:
- Kompiliert die Zuweisung?
- Ist ggf. ein Cast notwendig?
- Ist der Cast zur Laufzeit sicher?
Diese Trennung verhindert, dass Compile-Time- und Runtime-Regeln vermischt werden.
Typbaum als Pflichtwerkzeug
Vor jeder Beurteilung sollte ein Typbaum gezeichnet werden. Beispiel:
TierHundPudel
Katze
Dann lassen sich Aussagen schnell pruefen:
Tier t = new Hund();-> Upcast, erlaubtHund h = (Hund) t;-> Downcast, nur sicher wenn Objekt wirklich Hund/Pudel ist
Ohne diesen Typbaum entstehen in Aufgaben mit vielen Variablen schnell Denkfehler.
Compile-Time vs Runtime an Beispielen
Kompilierbar und sicher
Tier t = new Pudel();
Hund h = (Hund) t;
Kompilierbar, aber riskant
Tier t = new Katze();
Hund h = (Hund) t; // Laufzeitfehler
Nicht kompilierbar
Katze k = new Tier();
Das Blatt trainiert genau diese Unterschiede in mehreren Aufgabenvarianten.
Kovarianz bei Arrays kritisch einordnen
Die Array-Kovarianz ist historisch vorhanden, aber nicht voll typsicher. Das Blattbeispiel mit GeometrischeFigur[] und Kreis[] zeigt den klassischen Zielkonflikt:
- Flexibilitaet bei Zuweisungen
- moegliche
ArrayStoreExceptionzur Laufzeit
Didaktischer Vergleich:
- Arrays sind kovariant.
- Generics (
List<T>) sind invariant und dadurch strenger.
Dieser Vergleich hilft, moderne Java-API-Entscheidungen besser zu verstehen.
null in Typaufgaben sauber behandeln
null ist bei Referenztypen meist zuweisbar. Das bedeutet aber nur Typkompatibilitaet, nicht Nutzbarkeit.
Beispiel:
LebensmittelProdukt lmp = null;
Produkt p = lmp; // erlaubt
Danach bleibt jeder Methodenaufruf auf p potentiell gefaehrlich, solange p == null nicht geprueft wurde.
Aufgaben zu static und Vererbung
Das Blatt kombiniert Polymorphie mit Aussagen zu Klassenvariablen und Methodenregeln. Wichtige Klarstellungen:
static-Member gehoeren der Klasse.- Nicht-statische Methoden koennen auf statische Member zugreifen.
- Konstruktoren werden nicht vererbt.
protecteddient Erweiterbarkeit in Subklassen.
Diese Aussagen sollten immer zusammen mit konkreten Codebeispielen geuebt werden.
Uebungsformat fuer Partnerarbeit
- Jede Gruppe bekommt 12 Zuweisungen.
- Fuer jede Zuweisung werden drei Spalten ausgefuellt:
- kompiliert
- Cast noetig
- Laufzeitsicher
- Danach Gegencheck mit anderer Gruppe.
So wird aus Ankreuzwissen eine begruendete Typanalyse.
Laufzeitfehler reproduzierbar demonstrieren
Ein wichtiger Lernschritt ist bewusstes Reproduzieren von Fehlern:
ClassCastExceptionArrayStoreException
Wenn Lernende diese Fehler einmal selbst provozieren und erklaeren, verankern sich die Regeln deutlich besser als durch reine Theorie.
Bewertungsraster fuer OOP-II-Uebungen
- Typbeziehungen korrekt dargestellt.
- Zuweisungen korrekt klassifiziert.
- Cast-Risiken erkannt.
- Runtime-Fehler plausibel begruendet.
- Begriffe (Upcast, Downcast, Kovarianz) korrekt verwendet.
Transfer in reale Codebasen
In Produktivcode tauchen dieselben Fragen auf, nur mit mehr Klassen:
- API liefert Obertyp, konkrete Untertypen werden zur Laufzeit unterschieden.
- Falsche Castannahmen fuehren zu sporadischen Laufzeitfehlern.
- Unscharfe Typmodelle erschweren Wartung.
Das Blatt bereitet genau auf diese Situationen vor.
Abschluss der Vertiefung
Die Uebungsseite ist ein Kernkapitel fuer Typsicherheit in Java. Wer die dort trainierten Zuweisungs- und Castregeln wirklich beherrscht, kann polymorphen Code nicht nur schreiben, sondern auch korrekt analysieren und debuggen.
Abschlussserie zu Typbeziehungen
Zeichne fuer eine eigene Klassenhierarchie (mindestens 5 Klassen) einen Typbaum und pruefe 20 Zuweisungen.
Pro Zuweisung dokumentieren:
- kompiliert ja/nein
- Cast noetig ja/nein
- Laufzeitsicher ja/nein
- kurze Begruendung
Bonus:
- Baue bewusst zwei Beispiele ein, die kompilieren, aber zur Laufzeit scheitern.
Diese Serie trainiert exakt die Kompetenz, die das Uebungsblatt in vielen Einzelaufgaben aufbaut.
Pruefungsnahe Kurzfragen
- Was unterscheidet statischen von dynamischem Typ?
- Wann ist ein Downcast syntaktisch erlaubt, aber gefaehrlich?
- Warum kann Array-Kovarianz zu Laufzeitfehlern fuehren?
- Welche Information benoetigst du, um die Sicherheit eines Casts zu beurteilen?
Diese Fragen verdichten die Kernideen der gesamten Uebungsseite.
Weiterfuehrende Praxisaufgabe
Erstelle ein eigenes Mini-Projekt mit einer Oberklasse und mindestens drei Subklassen. Formuliere 15 Zuweisungen und 8 Casts.
Fuer jeden Fall dokumentieren:
- statischer Typ links/rechts
- dynamischer Typ des Objekts
- kompiliert ja/nein
- Laufzeit sicher ja/nein
Ergaenze mindestens einen Fall mit ArrayStoreException und einen mit ClassCastException. Dadurch wird die Trennung von Typpruefung und Laufzeitverhalten nachhaltig gefestigt.
Mini-Reflexion
In OOP-II-Aufgaben entscheidet selten Intuition, sondern fast immer ein sauber gezeichneter Typbaum. Wer diese Visualisierung konsequent nutzt, trennt automatisch zwischen Kompilierbarkeit und Laufzeitverhalten.
Zusatzaufgabe
Waehle aus dem Uebungsblatt drei Beispiele mit Casts aus und erweitere sie jeweils um einen sicheren instanceof-Check. Begruende, wann dadurch nur ein Laufzeitfehler verhindert wird und wann auch die Lesbarkeit des Codes verbessert wird.
Schlussgedanke
Polymorphie ist erst dann wirklich verstanden, wenn Zuweisungen nicht geraten, sondern begruendet werden. Das Blatt trainiert genau diese Begruendungskompetenz.
Eine saubere Typanalyse ist kein Zusatz, sondern die Grundlage dafuer, polymorphen Code spaeter sicher zu erweitern, zu testen und in Reviews nachvollziehbar zu begruenden.
