Informatik

Generische Klassen

Im Kapitel über Schnittstellen hast du einen Sortierer gebaut, der Bücher und Personen sortieren kann. Der Preis dafür: An jeder Stelle, an der du wieder an das konkrete Objekt wolltest, brauchtest du eine Typumwandlung.

Generische Klassen lösen dasselbe Problem – und behalten dabei den Typ.

Das Problem

Die Klasse Behaelter speichert genau ein Objekt. Sage voraus, was das Programm ausgibt – und wo es Ärger geben wird.

Auflösung

Die erste Ausgabe funktioniert: Inhalt: Hallo, Länge: 5.

Entfernst du die Schrägstriche, übersetzt das Programm weiterhin – und bricht erst beim Ausführen ab. Object verrät der IDE nicht, was wirklich im Behälter steckt. Der Fehler zeigt sich erst zur Laufzeit.

Zwei Nachteile also:

  1. Jede Entnahme braucht eine Typumwandlung.
  2. Ein falscher Typ fällt erst beim Ausführen auf.

Die Lösung

Eine generische Klasse bekommt einen Typparameter, der erst bei der Verwendung festgelegt wird. Die Klasse arbeitet mit diesem Platzhalter, als wäre er ein echter Typ.

  • class Behaelter<T> führt den Typparameter T ein. Der Buchstabe ist frei wählbar; üblich sind T (type), E (element) oder ContentType.
  • Innerhalb der Klasse benutzt man T wie einen normalen Typ – als Attributtyp, Parametertyp und Rückgabetyp.
  • Bei der Verwendung setzt man den echten Typ ein: Behaelter<String>.
  • Keine Typumwandlung mehr nötig – die IDE weiß, was drin ist.
  • Ein falscher Typ ist jetzt ein Übersetzungsfehler, kein Laufzeitfehler.

Ein Typparameter kann nur ein Objekttyp sein. Für elementare Typen nimmt man die zugehörigen Klassen: Integer statt int, Double statt double, Boolean statt boolean.

Entferne im Hauptprogramm die Schrägstriche vor b.setze(42); und lies die Fehlermeldung.

Beurteile: Warum ist es besser, wenn dieser Fehler beim Übersetzen auffällt?

Auflösung

Weil ein Übersetzungsfehler immer gefunden wird. Ein Laufzeitfehler zeigt sich nur, wenn der betroffene Programmweg auch ausgeführt wird – vielleicht erst beim Anwender.

Dasselbe Argument wie beim Geheimnisprinzip in der Einführungsphase: Je mehr die Sprache schon beim Übersetzen abfängt, desto weniger kann sich verstecken.

Eine generische Sammlung

Innerhalb der Klasse ist T ein Typ wie jeder andere: private T[] inhalt; und new T[pMaxGroesse]. Nirgends steht eine Typumwandlung.

Genau so sind auch die Klassen der NRW-Bibliothek gebaut, mit denen du im Kapitel über Datenstrukturen arbeitest: List<ContentType>, Stack<ContentType>, Queue<ContentType>.

Ein Unterschied zum „großen" Java: Dort lässt sich new T[n] nicht schreiben. Man behilft sich mit einem Object[] und einer Typumwandlung beim Herausgeben. Wenn du später in einer echten Java-Umgebung arbeitest und diese Fehlermeldung siehst, weißt du, woran es liegt – an der Idee der generischen Klasse ändert das nichts.

Aufgabe: Ein generischer Stapel

Diesen Datentyp lernst du im übernächsten Kapitel gründlich kennen. Hier baust du eine einfache Vorstufe.

Ein Stapel funktioniert wie ein Stapel Teller: Man legt oben auf und nimmt oben weg. Wer zuletzt kam, geht zuerst.

Setze die generische Klasse so um, dass alle Tests grün werden.

Tipp 1: Wo liegt oben?

Wenn anzahl Elemente auf dem Stapel liegen, steht das oberste an Index anzahl - 1. Der nächste freie Platz ist anzahl.

Tipp 2: Wegnehmen

Merke dir das oberste Element in einer Variablen, verringere anzahl um eins und gib das gemerkte Element zurück.

Den Platz im Feld musst du nicht löschen – er wird beim nächsten Auflegen überschrieben.

Tipp 3: Der leere Stapel

Drei Methoden müssen den leeren Stapel gesondert behandeln: oberstes und nimmWeg liefern dann null, und legeAuf darf bei vollem Stapel nichts tun.

Schreib die Prüfung nicht jedes Mal neu hin – du hast istLeer() und istVoll() ja gerade gebaut.

Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Zusatzaufgabe

Ein Stapel ist der natürliche Datentyp für die Rückgängig-Funktion eines Programms.

a) Baue ein kleines Zeichenprogramm mit Scratch for Java: Jeder Mausklick setzt einen Punkt, und die Rücktaste macht den letzten Punkt rückgängig.

b) Welchen Typparameter braucht dein Stapel dafür?

c) Was passiert, wenn jemand öfter die Rücktaste drückt, als Punkte gesetzt wurden? Prüfe, ob dein Programm das aushält.


Selbsttest

Generische Klassen

Teilbare URL erstellen

Abschnitte auswählen