Generics
Generics (generische Typen, Typparameter) sind Platzhalter in der Programmierung
(z.B. <T>), die es ermöglichen, Klassen, Schnittstellen und Methoden
mit verschiedenen Datentypen wiederverwendbar zu machen. Sie erhöhen die
Typsicherheit zur Kompilierzeit, da fehlerhafte Datentypen erkannt werden, bevor
das Programm läuft. Generics machen also Klassen und Methoden flexibel, ohne die
Typsicherheit zu verlieren.
Typische Schreibweise:
Hier bedeutet <String>: Diese Liste darf nur Zeichenketten enthalten.
Warum Generics?
Statt mit dem Datentyp Object zu arbeiten und später zu casten, kann
direkt der gewünschte Datentyp direkt verwendet werden. Ohne Generics können
leicht Laufzeitfehler entstehen:
ArrayList list = new ArrayList();
list.add("Max");
list.add(42);
String name = (String) list.get(1); // ClassCastException zur Laufzeit
Mit Generics wird der Fehler früh erkannt:
ArrayList<String> list = new ArrayList<>();
list.add("Max");
// list.add(42); // Compilerfehler
String name = list.get(0); // kein Cast notwendig
Vorteile:
- weniger Casts
- Fehler schon beim Kompilieren
- besser lesbarer Code
Eigene generische Klasse
Du kannst selbst Typparameter definieren, oft mit T (Type):
public class Box<T>
{
private T value;
public void set(T value)
{
this.value = value;
}
public T get()
{
return value;
}
}
Verwendung:
Box<Integer> punktzahl = new Box<>();
punktzahl.set(100);
Integer wert = punktzahl.get();
Box<String> textBox = new Box<>();
textBox.set("Hallo");
Generische Methoden
Nicht nur Klassen, auch Methoden können generisch sein:
public static <T> void printArray(T[] array)
{
for (T element : array)
{
System.out.println(element);
}
}
Aufruf:
String[] namen = {"Ada", "Linus"};
Integer[] zahlen = {1, 2, 3};
printArray(namen);
printArray(zahlen);
Bounded Type Parameters
Manchmal soll ein Typparameter eingeschränkt sein, z. B. auf Zahlen:
Erlaubt sind dann nur Unterklassen von Number (z. B. Integer, Double).
Wildcards
Wildcards nutzt man oft bei Collections.
? extends Typ
? extends Number bedeutet: unbekannter Typ, der Number oder eine
Unterklasse davon ist.
public static double sum(List<? extends Number> zahlen)
{
double s = 0;
for (Number n : zahlen)
{
s += n.doubleValue();
}
return s;
}
Du kannst sicher lesen, aber in der Regel nichts Neues hinzufügen.
? super Typ
? super Integer bedeutet: unbekannter Typ, der Integer oder eine Oberklasse
davon ist.
Hier kannst du Integer sicher hinzufügen.
Merksatz (PECS):
- Producer:
extends - Consumer:
super
Wichtige Hinweise
- Generics funktionieren nur mit Referenztypen, nicht mit primitiven Typen.
Also
List<Integer>stattList<int>. - Durch Type Erasure sind Typparameter zur Laufzeit weitgehend entfernt.
Deshalb ist z. B.
new T()nicht erlaubt. - Nutze den Diamond-Operator
<>, wenn der Typ rechts eindeutig ist.
Kurzfassung
Generics sorgen für sicheren und klaren Java-Code. Du definierst flexibel, welcher Typ verwendet wird, und bekommst viele Fehler schon beim Kompilieren statt erst zur Laufzeit.