Entschuldigung, aber du kannst nicht.
Die Platzhalterdeklaration von List<? extends Number> foo3
bedeutet, dass die Variable foo3
einen beliebigen Wert aus einer Typenfamilie enthalten kann (anstelle eines beliebigen Werts eines bestimmten Typs). Dies bedeutet, dass es sich bei diesen um rechtliche Aufträge handelt:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
List foo3
Vor diesem Hintergrund wäre es nach einer der oben genannten möglichen ArrayList
Zuweisungen legal , welche Art von Objekt Sie hinzufügen könnten :
- Sie können keine hinzufügen,
Integer
da foo3
dies auf eine zeigen könnte List<Double>
.
- Sie können kein hinzufügen,
Double
da foo3
dies auf ein zeigen könnte List<Integer>
.
- Sie können kein
Number
weil hinzufügenfoo3
dies auf ein zeigen könnte List<Integer>
.
Sie können kein Objekt hinzufügen, List<? extends T>
da Sie nicht garantieren können, auf welche Art von Objekt List
es wirklich zeigt. Sie können also nicht garantieren, dass das Objekt darin zulässig istList
. Die einzige "Garantie" ist, dass Sie nur daraus lesen können und eine T
oder eine Unterklasse von erhalten T
.
Die umgekehrte Logik gilt super
zList<? super T>
. Diese sind legal:
List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number
Sie können den spezifischen Typ T (z. B. Number
) nicht lesen, List<? super T>
da Sie nicht garantieren können, auf welche Art von Typ T List
wirklich zeigt. Die einzige "Garantie", die Sie haben, ist, dass Sie einen Wert vom Typ hinzufügen könnenT
(oder eine Unterklasse von T
) ohne die Integrität der Liste zu verletzen, auf die verwiesen wird.
Das perfekte Beispiel dafür ist die Signatur für Collections.copy()
:
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Beachten Sie, wie die src
Listendeklaration extends
es mir ermöglicht, eine Liste aus einer Familie verwandter Listentypen zu übergeben und dennoch zu gewährleisten, dass Werte vom Typ T oder Unterklassen von T erzeugt werden. Sie können der src
Liste jedoch keine Werte hinzufügen .
Das dest
Listendeklaration super
ermöglicht es mir, eine Liste aus einer Familie verwandter Listentypen zu übergeben und trotzdem zu garantieren, dass ich einen Wert eines bestimmten Typs T in diese Liste schreiben kann. Es kann jedoch nicht garantiert werden, dass die Werte des bestimmten Typs T gelesen werden, wenn ich aus der Liste lese.
Dank generischer Platzhalter kann ich jetzt jeden dieser Aufrufe mit dieser einzigen Methode ausführen:
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
Betrachten Sie diesen verwirrenden und sehr breiten Code, um Ihr Gehirn zu trainieren. Die auskommentierten Zeilen sind illegal und der Grund dafür ist ganz rechts in der Zeile angegeben (Sie müssen scrollen, um einige davon zu sehen):
List<Number> listNumber_ListNumber = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>(); // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Number>
List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();
List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>(); // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>(); // error - Double is not superclass of Number
//List<Integer> listInteger_ListNumber = new ArrayList<Number>(); // error - can assign only exactly <Integer>
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Integer>
//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer
List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer
List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a superclass of Integer
listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List<Number>
// These next 3 are compile errors for the same reason:
// You don't know what kind of List<T> is really
// being referenced - it may not be able to hold an Integer.
// You can't add anything (not Object, Number, Integer,
// nor Double) to List<? extends Number>
//listExtendsNumber_ListNumber.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>
listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List<Number> or List<Object>
listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List<Integer> (duh)
// This fails for same reason above - you can't
// guarantee what kind of List the var is really
// pointing to
//listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List<X> that is only allowed to hold X's
listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
List<? extends Number>
dies nicht "Liste von Objekten unterschiedlichen Typs, die sich alle erstreckenNumber
" bedeutet. Es bedeutet "Liste von Objekten eines einzelnen Typs, die sich erweiternNumber
".