Ein generischer Typ ist eine generische Klasse oder ein generisches Interface, das über Typen parametrisiert ist. Dadurch kann der Compiler die Typsicherheit für die Klasse oder das Interface durchsetzen.
Betrachte dieses nicht-generische Container-Interface:
class Container {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
Da es Object-Typen annimmt und zurückgibt, funktioniert es mit jedem Nicht-Primitivtyp. Das hat jedoch seinen Preis, denn mancher Code ruft get auf und erwartet Integer, während anderer Code set aufruft und Strings hinzufügt. Das Ergebnis ist eine Laufzeitausnahme.
Eine generische Klasse und ein generisches Interface haben die folgenden Formate:
class ClassName<T1, T2, ..., Tn> { ... }
interface InterfaceName<T1, T2, ..., Tn> { ... }
Der Abschnitt für die Typparameter, begrenzt durch spitze Klammern (<>), der auf den Klassen- oder Interface-Namen folgt, gibt die Typparameter (auch Typvariablen genannt) T1, T2, ..., und Tn an. Du kannst sie im Rumpf der Klasse oder des Interface verwenden, um generische Typsicherheit zu bekommen.
Hier ist die generische Version von Container:
class Container<E> {
private E object;
public void set(E object) { this.object = object; }
public E get() { return object; }
}
Wenn wir sie jetzt erstellen, müssen wir angeben, welchen Typ sie enthält, und der Compiler setzt diese Einschränkung durch:
// empty <> can infer from context
Container<String> stringContainer = new Container<>();
// compiler knows this is a String, so it is allowed
stringContainer.set("Some string");
// no cast needed, compiler knows it is a String
String result = stringContainer.get();
// this causes a compiler error:
stringContainer.set(42);