Ihre erste Option ist eine "strengere" Parametrierung. Das heißt, Sie definieren die Klasse T
mit einer Reihe von Einschränkungen und verwenden sie später mit List
. In Ihrer zweiten Methode ist die Parameterklasse T
generisch ohne Bedingungen und der Klassenparameter List
s ist definiert als Parameter T
.
Der zweite Weg ist auch syntaktisch anders, mit einem ?
anstelle der T
der ersten Option, weil Sie in der Parameterdefinition nicht den Typparameter T
definieren, sondern ihn verwenden, also den zweiten Methode kann nicht so spezifisch sein.
Der praktische Unterschied, der daraus entsteht, ist der der Vererbung. Ihre erste Methode muss ein Typ sein, der mit einer Superklasse von sich selbst vergleichbar ist, während der zweite Typ nur mit einem unbedingten / nicht verwandten Wenn Sie T
: Comparable
von Person
ändern, um Object
oder Person
(den Vererbungsbaum der Basisklasse) vergleichen zu können, funktioniert auch methodX
.
Für die Anrufer entspricht die 2. Version ungefähr
%Vor% Angenommen, ein Aufrufer ruft es mit einem Argument an, dessen konkreter Typ List<Foo>
ist. Typinferenz wird zu dem Schluss kommen, dass X=Foo
. Dann erhalten wir eine neue Gleichung über T von X
's gebunden
( A <: B
bedeutet, dass A ein Subtyp von B ist)
Wenn Foo
überhaupt vergleichbar ist, ist es fast sicher implements Comparable<Foo>
[2]
Ohne weitere Informationen wählt Inferenz T=Foo
.
Aus dem POV des Aufrufers unterscheiden sich die beiden Versionen nicht wirklich.
Im internen Methodenhauptteil hat die zweite Version keinen Zugriff auf den Typparameter X
, der in der Kompilierungsphase eingeführt wurde. Dies bedeutet, dass Sie nur von data
lesen können. Dinge wie
sind in Version 2 nicht möglich; Kein solches Problem in Version # 1 mit T
.
Allerdings können wir # 2 zu # 1 weiterleiten
%Vor% Das liegt daran, dass für den Compiler der Typ von data
wirklich List<X>
ist (er kennt die Secrete X
), so dass es kein Problem gibt, method1(data)
nach dem Schluss auf T1=X
[1] JLS3, 5.1.10 Capture-Konvertierung
[2] Gemäß dem Javadoc von Comparable
, Diese Schnittstelle erzwingt eine Gesamtordnung für die Objekte jeder Klasse, die sie implementiert. Das bedeutet, wenn Foo implements Comparable<W>
, W muss Foo oder sein eine super Art von Foo. Es ist ziemlich unwahrscheinlich für eine Unterklassenimplementierung, eine Gesamtordnung unter Objekten einer Superklasse zu definieren. Also W
sollte definitiv Foo
sein. Sonst würden lustige Dinge passieren. Das berüchtigte Beispiel ist "Timestamp", sein Javadoc (jetzt) erklärt, warum es nicht mit seinem Supertyp Date
Die erste Methode erwartet eine Liste von Elementen, die mit ihrer eigenen Klasse oder einem Supertyp davon verglichen werden können. Sagen wir, reelle Zahlen können mit jeder Art von Zahlen verglichen werden:
%Vor%Ein bisschen restriktiver, aber immer noch akzeptabel für Ihre erste Methode:
%Vor%Aber die zweite Methode unterscheidet sich eigentlich nicht sehr von dieser Version:
%Vor% Das heißt, Sie können T
durch eine unbenannte Wildcard ?
ersetzen, da sie nur einmal in der Methodensignatur verwendet wird. Es verwendet keine Konzepte wie dieselbe Klasse oder die eigene Klasse eines Objekts usw.