⚠ Hinweis zur Datenqualität: Die Daten dieser Seite wurden durch manuelle Analyse aller OOP-Ausarbeitungsaufgaben aus den offiziellen Prüfungsvorschlägen gewonnen und mithilfe von KI ausgewertet. Trotz sorgfältiger Prüfung können einzelne Einträge fehlerhaft oder unvollständig sein. Im Zweifelsfall mit den offiziellen Prüfungsunterlagen vergleichen.
⚠ Wichtiger Hinweis zur Vollständigkeit: Dieses Dokument basiert ausschließlich auf dem Aufgabentext und den offiziellen Musterlösungen. Alles, was nur aus einem Klassendiagramm oder Material zu entnehmen ist (konkrete Attribute, genaue Methodensignaturen, Assoziationen), kann hier nicht vollständig beschrieben werden. Solche Stellen sind mit [→ DIAGRAM] markiert. Fülle diese selbst anhand des Klassendiagramms der jeweiligen Aufgabe aus.

1 · Aufgabentypen — Was wird überhaupt gefragt?

Übersicht der wiederkehrenden Aufgabenformen aus 10 Jahren Abitur.
Aufgabentyp Schlüsselwörter im Text Häufigkeit Schwerpunkt
Klasse überführen & implementieren Überführen Sie … in Anweisungen einer OOP-Sprache und implementieren Sie sehr hoch Klassendiagramm → Java-Code
Methode implementieren Implementieren Sie die Methode … sehr hoch Algorithmus nach Beschreibung / Struktogramm
Serielle Schnittstelle Serial, readLine(), Kommunikationsprotokoll gegeben hoch Protokoll lesen, parsen, senden
Client/Server implementieren ServerSocket, Socket, Sitzungsprotokoll gegeben hoch Server-Hauptschleife + Protokoll-Parsing
RFID readCard() RFIDReader, readCard(), Prüfzeichen mittel STX/ETX-Framing + Prüfsumme
Controller run() Struktogramm in Material X, FunkModul, RFID mittel Struktogramm direkt in Code übersetzen
Sortiertes Einfügen Liste ist nach … sortiert, einfuegen() / hinzufuegenSortiert() mittel Position suchen, list.add(index, obj)
Singleton-Muster von einer Klasse genau ein Objekt, getInstance() selten Privater Konstruktor + statische Instanz
Binäre Suche Liste ist sortiert, binäre Suche selten low/max-Pointer-Schema
Algorithmen (Quicksort, Mischen etc.) teileArray(), mischen(), Random selten Algorithmus aus Pseudocode / Analogie ableiten

2 · Klasse überführen & implementieren — Schritt für Schritt

Der häufigste Aufgabentyp. Immer gleiche Struktur, immer gleiche Reihenfolge.
Faustregel: Überführen = UML → Java-Grundgerüst (Attribute, Konstruktor, Methodenköpfe). Implementieren = die Methodenkörper mit Logik füllen. Beides wird fast immer zusammen verlangt.

2.1 Reihenfolge im Klassenkörper

Feste Schreibreihenfolge (entspricht dem Klassendiagramm von oben nach unten)
1. Klassenkonstanten (static final - in C#: static readonly) — wenn im Diagramm unterstrichen und mit GROSSBUCHSTABEN
2. Statische Attribute (static) — z.B. autowert (unterstrichen im Diagramm)
3. Instanzattribute (in Diagramm-Reihenfolge)
4. Konstruktor(en)
5. Methoden (in Diagramm-Reihenfolge)

2.2 Attribute aus dem Klassendiagramm ablesen

Ohne Klassendiagramm nicht möglich. Die Attribute stehen vollständig im Diagramm. Merke nur: unterstrichene Attribute im Diagramm sind static in Java. Unterstrichene und GROß geschriebene Konstanten werden zu static final - in C#: static readonly.
UML-NotationJavaC#
- name : Stringprivate String name;private string name;
+ anzahl : intpublic int anzahl;public int anzahl;
# wert : double (vererbt)protected double wert;protected double wert;
- autowert : int = 0 (unterstrichen)private static int autowert = 0;private static int autowert = 0;
BASISPREIS : double = 10.0 (unterstrichen, CAPS)private static final double BASISPREIS = 10.0;private static readonly double BASISPREIS = 10.0;

2.3 Konstruktor-Grundgerüst

JavaStandard-Konstruktor-Muster
public ClassName([→ DIAGRAM: Parameter]) { // 1. Autowert-Zuweisung (falls vorhanden — siehe Sektion 3) this.id = …autowert…; // 2. Alle einfachen Attribute zuweisen this.name = name; this.wert = wert; // 3. Boolesche Flags auf Standardwert setzen this.aktiv = false; // 4. Listenattribute initialisieren (NIE vergessen!) this.items = new List<>(); // 5. Seiteneffekte (z.B. this zu anderer Liste hinzufügen — siehe Sektion 8) }
public ClassName([→ DIAGRAM: Parameter]) { // 1. Autowert-Zuweisung (falls vorhanden — siehe Sektion 3) this.id = …autowert…; // 2. Alle einfachen Attribute zuweisen this.name = name; this.wert = wert; // 3. Boolesche Flags auf Standardwert setzen this.aktiv = false; // 4. Listenattribute initialisieren (NIE vergessen!) this.items = new List<TYPE>(); // Typ immer angeben (kein <> in C#) // 5. Seiteneffekte (z.B. this zu anderer Liste hinzufügen — siehe Sektion 8) }

2.4 Listen immer im Konstruktor initialisieren

Jede Liste im Klassendiagramm → new List<>() im Konstruktor
Wird eine Liste im Konstruktor nicht initialisiert, gibt es zur Laufzeit eine NullPointerException. Das ist ein häufiger Fehler. Jedes Attribut vom Typ List<X> muss im Konstruktor mit this.listName = new List<>(); belegt werden — auch wenn die Liste zunächst leer ist.
Java
private List<Buchung> buchungen; public Mitglied(String name) { // ... this.buchungen = new List<>(); // ← IMMER! }
private List<Buchung> buchungen; public Mitglied(String name) { // ... this.buchungen = new List<Buchung>(); // ← IMMER! (Typ angeben, kein <> in C#) }

2.5 Abstrakte Klassen

Wann ist eine Klasse abstract?
Das Klassendiagramm zeigt es: Wenn der Klassenname kursiv geschrieben ist und es steht explizit <<abstract>> im Diagramm.

Abstrakte Methoden in der abstrakten Elternklasse: public abstract double berechne(); (kein Körper)
In der Unterklasse: @Override public double berechne() { … } - in C#: public override double berechne() { … }

3 · Das Autowert-Muster — Pre- vs. Post-Inkrement

Eines der häufigsten Fallstricke im Abitur. Die Entscheidung liegt ausschließlich im Klassendiagramm.
Goldene Regel: Den Startwert des autowert-Attributs liest du aus dem Klassendiagramm ab (es ist immer static, also unterstrichen). Er bestimmt eindeutig, ob Pre- oder Post-Inkrement verwendet wird. Die erste vergebene ID ist in beiden Fällen immer 1. Eine zugewiesene ID von 0, darf es in deinem Code nicht geben!
Diagramm zeigt: autowert = 0 (oder autowert*)
- autowert : int = 0 (unterstrichen = static)
Pre-Inkrement verwenden
Zuerst erhöhen, dann zuweisen.
Erste vergebene ID = 1
private static int autowert = 0; // Im Konstruktor: this.id = ++autowert; // Erste Ausführung: autowert wird 1, id = 1
Diagramm zeigt: autowert = 1 (oder autowert*)
- autowert : int = 1 (unterstrichen = static)
Post-Inkrement verwenden
Zuerst zuweisen, dann erhöhen.
Erste vergebene ID = 1
private static int autowert = 1; // Im Konstruktor: this.id = autowert++; // Erste Ausführung: id = 1, danach autowert = 2

3.1 Belegstellen aus den Musterlösungen

JahrKlasseDiagramm-StartwertCode in Lösung
2016 A*Kundeautonrthis.kdNr = ++autonr;
2017 B*MitgliedautowertmitgliedsNr = autowert++;
2017 B*BuchungautowertbuchungsNr = autowert++;
2018 BPerson (abstract)autoWert = 1this.personNr = autoWert++;
2021 AFahrerautowert = 0this.fahrernr = ++autowert;
2022 C*Bikeautowertautowert++; this.bikeID = autowert;
2024 BPersonautowert = 0this.id = ++autowert;
2025 APatientautowert = 1this.patientenNr = autowert++;
Sonderfall 2022 C (Bike): Hier wurde eine ungewöhnliche Variante verwendet — autowert++; this.bikeID = autowert; — was dasselbe Ergebnis wie Pre-Inkrement liefert, aber über zwei separate Zeilen. Schreibe lieber die Normalform (... = ++autowert oder ... = autowert++), die in allen anderen Jahren verwendet wird.
*Zweiter Sonderfall: In 2016 A, 2017 B und 2022 C wurde autowert keine Zahl im Klassendiagramm zugewiesen. Da sich hier Pre- (2016 A) als auch Post-Increment (2022 C) vorweisen lässt, kann man selbst entscheiden welche Variante man benutzen will.
⚠️ Aber beachte: wenn private static int autowert = 1;... = autowert++; und wenn private static int autowert = 0;... = ++autowert;!

4 · Listen — Verwendungsmuster

Die eigene List<T>-Klasse des Abiturs verhält sich ähnlich wie ArrayList, hat aber eine eigene API.

4.1 Bekannte Methoden der Abi-List-Klasse

Methode (Java)Methode (C#)Bedeutung
list.add(element)list.Add(element)Element am Ende anfügen
list.add(index, element)list.Insert(index, element)Element an Position index einfügen (restliche Elemente rücken nach rechts)
list.get(index)list[index]Element an Position index lesen (0-basiert)
list.remove(element)list.Remove(element)Objekt aus Liste entfernen
list.remove(index)list.RemoveAt(index)Element an Position entfernen, gibt Element zurück
list.size()list.CountAnzahl der Elemente
list.isEmpty()list.IsEmpty()Prüft ob leer
list.contains(element)list.Contains(element)Prüft ob Element enthalten
for (Typ t : list)foreach (Typ t in list)For-each-Schleife (sehr häufig im Abi)

4.2 Suchmethode — Standard-Muster

sucheX() / findeX() — immer gleiche Struktur
Ergebnisvariable auf null setzen, Liste iterieren, bei Treffer zuweisen. Am Ende zurückgeben. Wenn nur das erste Ergebnis gesucht wird: break oder vorzeitig return.
Java
public Spieler sucheSpieler(String name) { Spieler ergebnis = null; for (Spieler s : spieler) { if (s.getName().equals(name)) { ergebnis = s; break; // nur erstes Ergebnis } } return ergebnis; }
public Spieler sucheSpieler(string name) { Spieler ergebnis = null; foreach (Spieler s in spieler) { if (s.getName() == name) { ergebnis = s; break; // nur erstes Ergebnis } } return ergebnis; }

4.3 Sortiertes Einfügen — Standard-Muster

Liste ist nach X sortiert → neues Element an richtiger Position einfügen
Trigger im Aufgabentext: „Die Liste ist nach [Datum/Stunde/Wert] sortiert zu halten" oder „Die Methode fügt an der zeitlich korrekten Position ein".
Muster: Index mit While-Schleife suchen, dann list.add(index, element).
Java
// Bsp: Liste aufsteigend nach Datum sortiert halten int i = 0; while (i < liste.size() && liste.get(i).getDatum().isBefore(neuesDatum)) { i++; } liste.add(i, neuesElement); // an gefundener Position einfügen
// Bsp: Liste aufsteigend nach Datum sortiert halten int i = 0; while (i < liste.Count && liste[i].getDatum().isBefore(neuesDatum)) { i++; } liste.Insert(i, neuesElement); // an gefundener Position einfügen
Hinweis: Der genaue Vergleich (isBefore, compareTo, >, <) hängt vom Typ des Sortierkriteriums ab — steht im Aufgabentext oder Material. Nur das Grundmuster (Index-Suche + add(index, …)) ist garantiert konstant.

5 · Vererbung & abstrakte Klassen

Muster für extends, super(), @Override und instanceof.

5.1 Unterklassen-Konstruktor — immer mit super()

super() ist immer die erste Zeile im Unterklassen-Konstruktor
Alle Parameter, die zur Elternklasse gehören, werden via super() weitergegeben. Danach kommen nur noch die Attribute der Unterklasse selbst.
Java
public abstract class Person { protected String name; protected String vorname; public Person(String name, String vorname) { this.name = name; this.vorname = vorname; } public abstract double berechne(); } public class Mitarbeiter extends Person { private double gehalt; public Mitarbeiter(String name, String vorname, double gehalt) { super(name, vorname); // ← IMMER ERSTE ZEILE this.gehalt = gehalt; } @Override public double berechne() { return this.gehalt; } }
public abstract class Person { protected string name; protected string vorname; public Person(string name, string vorname) { this.name = name; this.vorname = vorname; } public abstract double berechne(); } public class Mitarbeiter : Person { private double gehalt; public Mitarbeiter(string name, string vorname, double gehalt) : base(name, vorname) { // ← base() steht nach der Signatur, nicht im Body this.gehalt = gehalt; } public override double berechne() { return this.gehalt; } }

5.2 instanceof + Cast — Standard-Muster

Wenn eine Liste Objekte der Elternklasse enthält, aber nur Unterklassen-Objekte bearbeitet werden sollen
Trigger: „Die Methode muss prüfen, ob es sich bei einer Person um ein Kunden-Objekt handelt"
Java
for (Person p : personen) { if (p instanceof Kunde) { Kunde k = (Kunde) p; // expliziter Cast // jetzt mit k arbeiten } }
foreach (Person p in personen) { if (p is Kunde) { Kunde k = (Kunde) p; // expliziter Cast (oder: p as Kunde) // jetzt mit k arbeiten } }

5.3 toString() in der Vererbungshierarchie

Java
// In der Unterklasse: super.toString() aufrufen + eigenes ergänzen @Override public String toString() { return "Reinigungskraft " + super.toString() + ", Stundensatz " + stundenSatz + " EURO"; }
// In der Unterklasse: base.ToString() aufrufen + eigenes ergänzen public override string ToString() { return "Reinigungskraft " + base.ToString() + ", Stundensatz " + stundenSatz + " EURO"; }

6 · Serielle Schnittstelle — Serial-Klasse

Wiederkehrendes Muster für Hardware-Kommunikation. Taucht in fast jedem zweiten Exam auf.

6.1 Serial-Konstruktor — immer gleiche Parameterliste

new Serial(port, baudrate, datenbits, stoppbits, parität)
Diese Parameterliste ist festgelegt und taucht in dieser Form in allen Jahren auf. Die konkreten Werte stehen im Aufgabentext.
// Aufgabentext: "9600 Baud, 8 Datenbits, 1 Stoppbit, keine Parität" Serial port = new Serial("COM1", 9600, 8, 1, 0); // ↑ ↑ ↑ ↑ ↑ // Port Baud Dat Stp Parität(0=none) // Aufgabentext: "2400 Baud, 8 Daten-, einem Stoppbit, ohne Paritätsbit" Serial serial = new Serial("COM1", 2400, 8, 1, 0);

6.2 Serial — Grundgerüst mit open/close

Serial com = new Serial([Port], [Baud], 8, 1, 0); if (com.open()) { // Kommunikation com.write([Befehl] + "\n"); // Zeile senden String antwort = com.readLine(); // Zeile lesen // ... com.close(); }

6.3 Protokoll parsen — Antwort verarbeiten

Der konkrete Aufbau des Protokolls (welche Zeichen, welche Trennzeichen, welche Feldlängen) steht ausschließlich im Material. Das Grundmuster ist aber konstant:
Java
// Typisches Muster: Antwort hat Rahmen, der abgeschnitten wird String temp = com.readLine(); temp = temp.substring(1, temp.length() - 1); // Rahmenzeichen entfernen // Typisches Muster: Werte durch Trennzeichen trennen String[] werte = temp.split(";"); int[] zahlen = new int[werte.length]; for (int i = 0; i < werte.length; i++) { zahlen[i] = Integer.parseInt(werte[i].trim()); } // Typisches Muster: ACK/NAK-Schleife do { barcode = com.readLine(); if (pruefeBarcode(barcode)) { com.write(ACK); } else { com.write(NAK); } } while (zeichen == NAK);
// Typisches Muster: Antwort hat Rahmen, der abgeschnitten wird string temp = com.readLine(); temp = temp.Substring(1, temp.Length - 2); // Rahmenzeichen entfernen (C#: Substring(start, length)!) // Typisches Muster: Werte durch Trennzeichen trennen string[] werte = temp.Split(';'); int[] zahlen = new int[werte.Length]; for (int i = 0; i < werte.Length; i++) { zahlen[i] = int.Parse(werte[i].Trim()); } // Typisches Muster: ACK/NAK-Schleife do { barcode = com.readLine(); if (pruefeBarcode(barcode)) { com.write(ACK); } else { com.write(NAK); } } while (zeichen == NAK);

7 · RFID readCard() — STX/ETX-Rahmen-Muster

Taucht in identischer Form in ABI 2021 A und ABI 2025 B auf. Sehr gut lernbar.
Erkennungsmerkmal: Aufgabentext erwähnt RFIDReader, readCard(), Prüfzeichen, calcCheckChar() und ein „Datenformat in Material X". Das Grundmuster ist in allen Jahren identisch.
Protokoll-Aufbau (immer: STX | Daten | Prüfzeichen | ETX)
STX = 0x02 (Start of Text) — auf dieses Zeichen wird gewartet
Daten = [→ DIAGRAM/MATERIAL: Anzahl der Datenbytes — z.B. 6 oder 7]
Prüfzeichen = 1 Byte, berechnet via calcCheckChar()
ETX = 0x03 (End of Text) — wird überprüft
JavareadCard() — vollständiges Muster
public String readCard() { String response = ""; char checkValue; char[] data = new char[[→ MATERIAL: Anzahl Datenbytes, z.B. 6 oder 7]]; while (readChar() != 0x02); // warte auf STX for (int i = 0; i < data.length; i++) { data[i] = readChar(); // Datenbytes lesen } checkValue = readChar(); // Prüfzeichen lesen if (readChar() == 0x03) { // ETX prüfen if (checkValue == calcCheckChar(data)) { response = new String(data); } // Prüfzeichen falsch → response bleibt "" } return response; // "" = Fehlerfall }
public string readCard() { string response = ""; char checkValue; char[] data = new char[[→ MATERIAL: Anzahl Datenbytes, z.B. 6 oder 7]]; while (readChar() != 0x02); // warte auf STX for (int i = 0; i < data.Length; i++) { data[i] = readChar(); // Datenbytes lesen } checkValue = readChar(); // Prüfzeichen lesen if (readChar() == 0x03) { // ETX prüfen if (checkValue == calcCheckChar(data)) { response = new string(data); } // Prüfzeichen falsch → response bleibt "" } return response; // "" = Fehlerfall }
Variation 2025 B: Dort wird response direkt als String aufgebaut statt als char[] — die Logik (warte auf STX, lies Daten, lies Prüfzeichen, prüfe ETX) ist identisch. Beide Varianten sind akzeptiert.

8 · Controller run() — FunkModul + RFID

Taucht in ABI 2021 A und ABI 2025 B nahezu identisch auf. Struktogramm direkt übersetzen.
Der genaue Ablauf steht im Struktogramm (Material X). Ohne das Struktogramm kann man den Methodenkörper nicht vollständig implementieren. Das Grundgerüst des Konstruktors und der äußeren Schleife ist jedoch konstant.
JavaController — Konstruktor-Muster (konstant über alle Jahre)
public class Controller { private FunkModul funkModul; private RFIDReader reader; private [→ DIAGRAM: weiteres Attribut, z.B. Fahrzeug/Durchgang]; public Controller(String comPort, [→ DIAGRAM: Typ name]) { funkModul = new FunkModul(); this.[attribut] = [parameter]; Serial serial = new Serial(comPort, 9600, 8, 1, 0); if (serial.open()) { reader = new RFIDReader(serial); } } public void run() { char response; String rfidKennung; while (true) { if (reader.isCardAvailable()) { rfidKennung = reader.readCard(); if (!rfidKennung.isEmpty()) { // UNLOCK-Kommando + FunkModul senden funkModul.send("UNLOCK" + [→ STRUKTOGRAMM: Felder]); response = funkModul.receive(); if (response == 0x06) { // ACK [→ STRUKTOGRAMM: Entsperr-Logik + Timer] } else { display("Karte nicht authorisiert"); } } else { display("Karte nicht lesbar"); } } } } }
public class Controller { private FunkModul funkModul; private RFIDReader reader; private [→ DIAGRAM: weiteres Attribut, z.B. Fahrzeug/Durchgang]; public Controller(string comPort, [→ DIAGRAM: Typ name]) { funkModul = new FunkModul(); this.[attribut] = [parameter]; Serial serial = new Serial(comPort, 9600, 8, 1, 0); if (serial.open()) { reader = new RFIDReader(serial); } } public void run() { char response; string rfidKennung; while (true) { if (reader.isCardAvailable()) { rfidKennung = reader.readCard(); if (!rfidKennung.isEmpty()) { // UNLOCK-Kommando + FunkModul senden funkModul.send("UNLOCK" + [→ STRUKTOGRAMM: Felder]); response = funkModul.receive(); if (response == 0x06) { // ACK [→ STRUKTOGRAMM: Entsperr-Logik + Timer] } else { display("Karte nicht authorisiert"); } } else { display("Karte nicht lesbar"); } } } } }

9 · Client/Server — Protokoll-basierte Implementierung

Taucht in fast jedem Jahr auf. Das Sitzungsprotokoll steht immer im Aufgabentext — daraus wird der Code direkt abgeleitet.

9.1 Server-Grundgerüst

Server = ServerSocket + while(true) + accept()
Die äußere Endlosschleife mit serverSocket.accept() ist in jedem Server-Beispiel gleich. Was sich ändert: die Protokoll-Verarbeitung im Inneren.
Java
public class MeinServer { private ServerSocket server; private [→ DIAGRAM: Verwaltungs-Objekt] verwaltung; public MeinServer(int port, [→ DIAGRAM] verwaltung) { this.server = new ServerSocket(port); this.verwaltung = verwaltung; } public void startServer() { while (true) { Socket sc = server.accept(); // Begrüßung senden (steht im Protokoll im Aufgabentext) sc.write("+OK …\n"); String anforderung = sc.readLine(); while (!anforderung.equals("quit")) { // Kommando verarbeiten String[] werte = anforderung.split(";"); switch (werte[0]) { case "[KOMMANDO1]": ; break; case "[KOMMANDO2]": ; break; } anforderung = sc.readLine(); } sc.close(); } } }
public class MeinServer { private ServerSocket server; private [→ DIAGRAM: Verwaltungs-Objekt] verwaltung; public MeinServer(int port, [→ DIAGRAM] verwaltung) { this.server = new ServerSocket(port); this.verwaltung = verwaltung; } public void startServer() { while (true) { Socket sc = server.accept(); // Begrüßung senden (steht im Protokoll im Aufgabentext) sc.write("+OK …\n"); string anforderung = sc.readLine(); while (anforderung != "quit") { // Kommando verarbeiten string[] werte = anforderung.Split(';'); switch (werte[0]) { case "[KOMMANDO1]": ; break; case "[KOMMANDO2]": ; break; } anforderung = sc.readLine(); } sc.close(); } } }

9.2 Protokoll-Parsing — Wie man Kommandos erkennt

Protokoll-Zeichen im TextBedeutung im Code
> +OK …Server sendet: sc.write("+OK …\n")
> -ERR …Server sendet: sc.write("-ERR …\n")
< kommando;wert1;wert2Client sendet, Server liest: sc.readLine() → split(";") → werte[0] = "kommando"
< quitSchleifenabbruch: while (!anforderung.equals("quit"))
Antwort beginnt mit +OKPrüfung: antwort.startsWith("+OK")

9.3 String → Zahlen umwandeln

Java
// Steht häufig als Hinweis im Aufgabentext: int i = Integer.parseInt(werte[1]); double d = Double.parseDouble(werte[2]); Date dt = Date.parseDate(werte[3]); // wenn Date-Klasse vorhanden
// Steht häufig als Hinweis im Aufgabentext: int i = int.Parse(werte[1]); double d = double.Parse(werte[2]); Date dt = Date.parseDate(werte[3]); // wenn Date-Klasse vorhanden

9.4 Anmelden-Methode — Klassiker

Java
// Muster: gib Objekt zurück wenn Credentials stimmen, sonst null public Konto anmelden(String iban, int pin) { for (Konto k : konten) { if (k.getIban().equals(iban) && k.login(pin)) { return k; } } return null; }
// Muster: gib Objekt zurück wenn Credentials stimmen, sonst null public Konto anmelden(string iban, int pin) { foreach (Konto k in konten) { if (k.getIban() == iban && k.login(pin)) { return k; } } return null; }

10 · Konstruktor-Seiteneffekte

Manchmal fügt ein Konstruktor das neue Objekt selbst zu einer anderen Klasse hinzu — oder erstellt ein abhängiges Objekt automatisch.
Erkennungsmerkmal im Aufgabentext: Formulierungen wie
— „Der Konstruktor setzt die aktuelle Zeit als Startzeit."
— „Ein Behandlungsplan wird bei Aufnahme eines Patienten erstellt."
— „Beim Abonnieren wird die bidirektionale Beziehung vollständig implementiert."
JahrKlasseSeiteneffekt im Konstruktor
2020 A Ticket this.kunde.hinzufuegenTicket(this);
Ticket fügt sich selbst beim Kunden hinzu
2021 A Lieferauftrag this.start = new DateTime();
Aktuelle Zeit wird automatisch als Start gesetzt
2024 A Teilnahme chor.getTeilnahmen().add(index, this);
Sortiertes Einfügen direkt im Konstruktor
2025 A Patient this.abteilung.aufnehmenPatient(this); und this.behandlungsplan = new Behandlungsplan(this);
Patient meldet sich selbst bei der Abteilung an + erstellt eigenen Behandlungsplan
Wann Seiteneffekte auftreten — Checkliste
✓ Aufgabentext beschreibt was „bei Erzeugung" passiert
✓ Aufgabentext erwähnt, dass eine andere Liste/Objekt aktualisiert wird
✓ Eine Assoziation im Klassendiagramm deutet auf eine bidirektionale Beziehung hin
✗ Fehlt dieser Hinweis → kein Seiteneffekt einbauen

11 · Singleton-Entwurfsmuster

Taucht selten auf, aber wenn, dann immer in identischer Form (ABI 2020 A). Auswendig lernbar.
Erkennungsmerkmal: Text enthält explizit „von einer Klasse genau ein Objekt", „Singleton", oder „getInstance()".
JavaSingleton-Muster — vollständig
public class Wissensdatenbank { // Bestehende Attribute und Methoden bleiben erhalten private List<Loesung> loesungen; // Singleton-Ergänzungen: private static Wissensdatenbank instance = null; private Wissensdatenbank() { // privater Konstruktor loesungen = new List<>(); } public static Wissensdatenbank getInstance() { if (instance == null) { instance = new Wissensdatenbank(); } return instance; } // ... restliche Methoden }
public class Wissensdatenbank { // Bestehende Attribute und Methoden bleiben erhalten private List<Loesung> loesungen; // Singleton-Ergänzungen: private static Wissensdatenbank instance = null; private Wissensdatenbank() { // privater Konstruktor loesungen = new List<Loesung>(); // Typ angeben, kein <> in C# } public static Wissensdatenbank getInstance() { if (instance == null) { instance = new Wissensdatenbank(); } return instance; } // ... restliche Methoden }

12 · Binäre Suche

ABI 2024 B. Erkennungsmerkmal: „Liste ist sortiert" + „binäre Suche" oder „Laufzeit optimieren".
JavaBinäre Suche — vollständiges Muster (aus ABI 2024 B)
public Ticket sucheTicket(String ticketNummer) { if (tickets.isEmpty()) return null; int low = 0; int max = tickets.size() - 1; // Achtung: size()-1, nicht size() while (low != max) { int pointer = (low + max) / 2; if (ticketNummer.equals(tickets.get(pointer).getTicketnummer())) { return tickets.get(pointer); } if (ticketNummer.compareTo(tickets.get(pointer).getTicketnummer()) > 0) { low = pointer + 1; // gesuchtes liegt rechts } else { max = pointer - 1; // gesuchtes liegt links } } return null; }
public Ticket sucheTicket(string ticketNummer) { if (tickets.IsEmpty()) return null; int low = 0; int max = tickets.Count - 1; // Achtung: Count-1, nicht Count while (low != max) { int pointer = (low + max) / 2; if (ticketNummer == tickets[pointer].getTicketnummer()) { return tickets[pointer]; } if (string.Compare(ticketNummer, tickets[pointer].getTicketnummer()) > 0) { low = pointer + 1; // gesuchtes liegt rechts } else { max = pointer - 1; // gesuchtes liegt links } } return null; }

13 · Doppelt verkettete Liste (manuelle Implementierung)

ABI 2022 C (Bike) und ABI 2022 B (Buchungen als verkettete Liste). Erkennungsmerkmal: „Demontage in umgekehrter Reihenfolge" / „naechste + vorherige".
Unterschied zur Standard-List<T>: Hier hat jedes Objekt selbst Zeiger auf das nächste/vorherige Objekt (naechste, vorherige) — wie eine klassische Linked List. Die List<T>-Klasse des Abiturs wird nicht verwendet.
// Klasse mit Zeigern auf Vorgänger und Nachfolger public abstract class Komponente { private Komponente naechste; // → Nachfolger private Komponente vorherige; // → Vorgänger // ... } // Hinten anfügen (Bike-Konstruktor): letzteKomp.setNaechste(komp); komp.setVorherige(letzteKomp); letzteKomp = komp; // Rückwärts traversieren (von letzter zu erster): Komponente aktuell = letzteKomp; while (aktuell != null) { // verarbeite aktuell aktuell = aktuell.getVorherige(); }

14 · Schnell-Referenz: Schlüsselwörter → Muster

Erkenne am Aufgabentext sofort, welches Muster gefragt ist.
Schlüsselwort / Phrase im Aufgabentext → Muster / Sektion
„Überführen Sie … und implementieren Sie"→ Klasse überführen (Sektion 2), Autowert prüfen (Sektion 3)
autowert : int = 0" (unterstrichen, im Diagramm)++autowert (Sektion 3)
autowert : int = 1" (unterstrichen, im Diagramm)autowert++ (Sektion 3)
Liste als Attribut vorhandennew List<>() im Konstruktor (Sektion 4)
„Liste ist … sortiert zu halten" / „einfuegen()"→ Sortiertes Einfügen (Sektion 4.3)
Klasse in kursiv im Diagramm / <<abstract>>abstract class + abstract-Methoden (Sektion 5)
„extends" / Vererbung sichtbar im Diagrammsuper(…) als erste Konstruktorzeile (Sektion 5.1)
„prüfen ob Person ein Kunden-Objekt ist"instanceof + Cast (Sektion 5.2)
Serial, Baudrate, Datenbits, Stoppbits, Paritätnew Serial(port, baud, 8, 1, 0) (Sektion 6)
RFIDReader, readCard(), Prüfzeichen, calcCheckChar()→ STX/ETX-Muster (Sektion 7)
FunkModul, Struktogramm in Material X, Controller→ Controller run()-Muster (Sektion 8)
Sitzungsprotokoll im Aufgabentext (> +OK, < kommando)→ Client/Server (Sektion 9)
„bei Erzeugung wird …" / „bei Aufnahme wird erstellt"→ Konstruktor-Seiteneffekt (Sektion 10)
„von einer Klasse genau ein Objekt" / „Singleton"→ Singleton-Muster (Sektion 11)
„Liste ist sortiert" + „Laufzeit optimieren" / „binäre Suche"→ Binäre Suche (Sektion 12)
„Demontage in umgekehrter Reihenfolge" / „naechste + vorherige"→ Doppelt verkettete Liste (Sektion 13)