⚠ 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.
Systematische Analyse aller OOP-Implementierungsaufgaben aus den Hessischen Abiturprüfungen (Java)
2016–2025. Dieses Dokument zeigt wiederkehrende Muster, damit du jede Aufgabe strukturiert
lösen kannst — ohne freies Denken, nur Pattern-Matching.
⚠ 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
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-Notation
Java
C#
- name : String
private String name;
private string name;
+ anzahl : int
public 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
publicClassName([→ DIAGRAM: Parameter]) {
// 1. Autowert-Zuweisung (falls vorhanden — siehe Sektion 3)this.id = …autowert…;// 2. Alle einfachen Attribute zuweisenthis.name = name;this.wert = wert;// 3. Boolesche Flags auf Standardwert setzenthis.aktiv = false;// 4. Listenattribute initialisieren (NIE vergessen!)this.items = new List<>();// 5. Seiteneffekte (z.B. this zu anderer Liste hinzufügen — siehe Sektion 8)
}
publicClassName([→ DIAGRAM: Parameter]) {
// 1. Autowert-Zuweisung (falls vorhanden — siehe Sektion 3)this.id = …autowert…;// 2. Alle einfachen Attribute zuweisenthis.name = name;this.wert = wert;// 3. Boolesche Flags auf Standardwert setzenthis.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.
privateList<Buchung> buchungen;
publicMitglied(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
Jahr
Klasse
Diagramm-Startwert
Code in Lösung
2016 A*
Kunde
autonr
this.kdNr = ++autonr;
2017 B*
Mitglied
autowert
mitgliedsNr = autowert++;
2017 B*
Buchung
autowert
buchungsNr = autowert++;
2018 B
Person (abstract)
autoWert = 1
this.personNr = autoWert++;
2021 A
Fahrer
autowert = 0
this.fahrernr = ++autowert;
2022 C*
Bike
autowert
autowert++; this.bikeID = autowert;
2024 B
Person
autowert = 0
this.id = ++autowert;
2025 A
Patient
autowert = 1
this.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.Count
Anzahl 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
publicSpieler sucheSpieler(String name) {
Spieler ergebnis = null;
for (Spieler s : spieler) {
if (s.getName().equals(name)) {
ergebnis = s;
break; // nur erstes Ergebnis
}
}
return ergebnis;
}
publicSpieler 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 haltenint 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 haltenint 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.
Wiederkehrendes Muster für Hardware-Kommunikation. Taucht in fast jedem zweiten Exam auf.
6.1Serial-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 = newSerial("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 = newSerial("COM1", 2400, 8, 1, 0);
6.2 Serial — Grundgerüst mit open/close
Serial com = newSerial([Port], [Baud], 8, 1, 0);
if (com.open()) {
// Kommunikation
com.write([Befehl] + "\n"); // Zeile sendenString 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 wirdString temp = com.readLine();
temp = temp.substring(1, temp.length() - 1); // Rahmenzeichen entfernen// Typisches Muster: Werte durch Trennzeichen trennenString[] 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-Schleifedo {
barcode = com.readLine();
if (pruefeBarcode(barcode)) {
com.write(ACK);
} else {
com.write(NAK);
}
} while (zeichen == NAK);
// Typisches Muster: Antwort hat Rahmen, der abgeschnitten wirdstring temp = com.readLine();
temp = temp.Substring(1, temp.Length - 2); // Rahmenzeichen entfernen (C#: Substring(start, length)!)// Typisches Muster: Werte durch Trennzeichen trennenstring[] 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-Schleifedo {
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.
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
publicStringreadCard() {
String response = "";
char checkValue;
char[] data = new char[[→ MATERIAL: Anzahl Datenbytes, z.B. 6 oder 7]];
while (readChar() != 0x02);// warte auf STXfor (int i = 0; i < data.length; i++) {
data[i] = readChar(); // Datenbytes lesen
}
checkValue = readChar();// Prüfzeichen lesenif (readChar() == 0x03) { // ETX prüfenif (checkValue == calcCheckChar(data)) {
response = newString(data);
}
// Prüfzeichen falsch → response bleibt ""
}
return response; // "" = Fehlerfall
}
public stringreadCard() {
string response = "";
char checkValue;
char[] data = new char[[→ MATERIAL: Anzahl Datenbytes, z.B. 6 oder 7]];
while (readChar() != 0x02);// warte auf STXfor (int i = 0; i < data.Length; i++) {
data[i] = readChar(); // Datenbytes lesen
}
checkValue = readChar();// Prüfzeichen lesenif (readChar() == 0x03) { // ETX prüfenif (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 classController {
privateFunkModul funkModul;
privateRFIDReader reader;
private[→ DIAGRAM: weiteres Attribut, z.B. Fahrzeug/Durchgang];
publicController(String comPort, [→ DIAGRAM: Typ name]) {
funkModul = new FunkModul();this.[attribut] = [parameter];Serial serial = newSerial(comPort, 9600, 8, 1, 0);
if (serial.open()) {
reader = new RFIDReader(serial);
}
}
public voidrun() {
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 classController {
privateFunkModul funkModul;
privateRFIDReader reader;
private[→ DIAGRAM: weiteres Attribut, z.B. Fahrzeug/Durchgang];
publicController(string comPort, [→ DIAGRAM: Typ name]) {
funkModul = new FunkModul();this.[attribut] = [parameter];Serial serial = newSerial(comPort, 9600, 8, 1, 0);
if (serial.open()) {
reader = new RFIDReader(serial);
}
}
public voidrun() {
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");
}
}
}
}
}
Schleifenabbruch: while (!anforderung.equals("quit"))
Antwort beginnt mit +OK
Prü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 nullpublicKonto 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 nullpublicKonto 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."
Jahr
Klasse
Seiteneffekt 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()".
public classWissensdatenbank {
// Bestehende Attribute und Methoden bleiben erhaltenprivateList<Loesung> loesungen;
// Singleton-Ergänzungen:private staticWissensdatenbank instance = null;privateWissensdatenbank() {// privater Konstruktor loesungen = newList<Loesung>();// Typ angeben, kein <> in C# }public staticWissensdatenbankgetInstance() {if (instance == null) { instance = newWissensdatenbank(); }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)
publicTicketsucheTicket(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;
}
publicTicketsucheTicket(string ticketNummer) {
if (tickets.IsEmpty()) return null;
int low = 0;
int max = tickets.Count - 1; // Achtung: Count-1, nicht Countwhile (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.