Ein generischer Typ ist eine generische Klasse oder Schnittstelle, die über Typen parametrisiert wird. Die folgende Box-Klasse wird geändert, um das Konzept zu demonstrieren.
Eine einfache Box-Klasse
Untersuchen Sie zunächst eine nicht generische Box-Klasse, die mit Objekten eines beliebigen Typs arbeitet. Es müssen nur zwei Methoden bereitgestellt werden: set, das der Box ein Objekt hinzufügt, und get, das es abruft:
Da die Methoden ein Objekt akzeptieren oder zurückgeben, können Sie alles übergeben, was Sie möchten , vorausgesetzt, es ist nicht einer der primitiven Typen. Es gibt keine Möglichkeit, zur Kompilierungszeit zu überprüfen, wie die Klasse verwendet wird. Ein Teil des Codes platziert möglicherweise eine Ganzzahl in das Feld und erwartet, dass Ganzzahlen daraus entfernt werden, während ein anderer Teil des Codes fälschlicherweise einen String übergibt, was zu einem Laufzeitfehler führt.
Eine generische Version der Box-Klasse
Eine generische Klasse wird im folgenden Format definiert:
class name<T1, T2, ..., Tn> { /* ... */ }
Zum Aktualisieren der Box-Klasse Um Generika zu verwenden, erstellen Sie eine generische Typdeklaration, indem Sie den Code „public class Box“ in „public class Box < T > „. Dadurch wird die Typvariable T eingeführt, die überall in der Klasse verwendet werden kann.
Mit dieser Änderung wird die Box-Klasse zu:
Wie Sie sehen können, sind alle Vorkommen von Object Ersetzt durch T. Eine Typvariable kann ein beliebiger nicht primitiver Typ sein, den Sie angeben: ein beliebiger Klassentyp, ein beliebiger Schnittstellentyp, ein beliebiger Array-Typ oder sogar eine andere Typvariable.
Dieselbe Technik kann zum Erstellen angewendet werden Generische Schnittstellen.
Konventionen für die Benennung von Typparametern
Konventionell sind Typparameternamen einzelne Großbuchstaben. Dies steht in scharfem Kontrast zu den Konventionen zur Benennung von Variablen, die Sie bereits kennen, und das aus gutem Grund: Ohne diese Konvention wäre es schwierig, den Unterschied zwischen einer Typvariablen und einem normalen Klassen- oder Schnittstellennamen zu erkennen.
Die am häufigsten verwendeten Typparameternamen sind:
- E-Element (wird häufig vom Java Collections Framework verwendet)
- K-Key
- N – Nummer
- T – Typ
- V – Wert
- S, U, V usw. – 2., 3., 4. Typ
Diese Namen werden in der gesamten Java SE-API und im Rest dieser Lektion verwendet.
Aufrufen und Instanziieren eines generischen Typs
Verweisen auf die generische Box-Klasse Innerhalb Ihres Codes müssen Sie einen generischen Typaufruf ausführen, der T durch einen konkreten Wert ersetzt, z. B. Integer:
Box<Integer> integerBox;
Sie können sich einen generischen Typaufruf als ähnlich wie einen normalen Methodenaufruf vorstellen, aber anstatt ein Argument an am zu übergeben Nach dieser Methode übergeben Sie ein Typargument – in diesem Fall eine Ganzzahl – an die Box-Klasse selbst.
Wie jede andere Variablendeklaration erstellt dieser Code kein neues Box-Objekt. Es wird lediglich deklariert, dass integerBox einen Verweis auf eine „Box of Integer“ enthält. Auf diese Weise wird Box < Integer > gelesen.
Ein Aufruf eines generischen Typs wird allgemein als parametrisierter Typ bezeichnet.
Um diese Klasse zu instanziieren, verwenden Sie wie gewohnt das neue Schlüsselwort, setzen Sie jedoch < Ganzzahl > zwischen dem Klassennamen und der Klammer:
Box<Integer> integerBox = new Box<Integer>();
Der Diamant
In Java SE 7 und höher können Sie die zum Aufrufen des Konstruktors einer generischen Klasse erforderlichen Typargumente durch einen leeren Satz von Typargumenten ersetzen (< >), solange der Compiler die Typargumente aus dem Kontext ermitteln oder ableiten kann. Dieses Paar spitzer Klammern, < >, wird informell als Diamant bezeichnet. Beispielsweise können Sie eine Instanz von Box < Integer > mit der folgenden Anweisung erstellen:
Box<Integer> integerBox = new Box<>();
Weitere Informationen zur Diamantnotation und Typinferenz finden Sie unter Typinferenz.
Mehrere Typparameter
Wie bereits erwähnt, Eine generische Klasse kann mehrere Typparameter haben.Beispiel: Die generische OrderedPair-Klasse, die die generische Pair-Schnittstelle implementiert:
Die folgenden Anweisungen erstellen zwei Instanziierungen der OrderedPair-Klasse:
Der Code new OrderedPair < String, Integer >, instanziiert K als String und V als Integer. Daher sind die Parametertypen des OrderedPair-Konstruktors String bzw. Integer. Aufgrund von Autoboxing ist es gültig, einen String und ein Int an die Klasse zu übergeben.
Wie in The Diamond erwähnt, weil a Der Java-Compiler kann die K- und V-Typen aus der Deklaration OrderedPair < String, Integer > ableiten. Diese Anweisungen können mit Diamantnotation gekürzt werden:
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
Befolgen Sie zum Erstellen einer generischen Schnittstelle die gleichen Konventionen wie zum Erstellen einer generischen Klasse.
Parametrisierte Typen
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));