Désolé, mais vous ne pouvez pas.
La déclaration générique de List<? extends Number> foo3
signifie que la variable foo3
peut contenir n'importe quelle valeur d'une famille de types (plutôt que n'importe quelle valeur d'un type spécifique). Cela signifie que l'une de ces cessions est légale:
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
Donc, étant donné cela, quel type d'objet pourriez-vous ajouter à List foo3
cela serait légal après l'une des ArrayList
affectations possibles ci-dessus :
- Vous ne pouvez pas ajouter un
Integer
car il foo3
pourrait pointer vers un fichier List<Double>
.
- Vous ne pouvez pas ajouter un
Double
car il foo3
pourrait pointer vers un fichier List<Integer>
.
- Vous ne pouvez pas ajouter un
Number
car il foo3
pourrait pointer vers un fichier List<Integer>
.
Vous ne pouvez pas ajouter d'objet, List<? extends T>
car vous ne pouvez pas garantir le type List
auquel il pointe réellement, vous ne pouvez donc pas garantir que l'objet est autorisé dans cela List
. La seule "garantie" est que vous ne pouvez lire qu'à partir de celui-ci et que vous obtiendrez une T
ou une sous-classe de T
.
La logique inverse s'applique à super
, par exemple List<? super T>
. Ceux-ci sont légaux:
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
Vous ne pouvez pas lire le type spécifique T (par exemple Number
) à partir de List<? super T>
parce que vous ne pouvez pas garantir quel type List
il pointe réellement. La seule «garantie» dont vous disposez est que vous pouvez ajouter une valeur de type T
(ou toute sous-classe de T
) sans violer l'intégrité de la liste pointée.
L'exemple parfait en est la signature pour Collections.copy()
:
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Remarquez comment la src
déclaration de liste utilise extends
pour me permettre de passer n'importe quelle liste d'une famille de types de liste liés tout en garantissant qu'elle produira des valeurs de type T ou des sous-classes de T. Mais vous ne pouvez pas ajouter à la src
liste.
La dest
déclaration de liste utilise super
pour me permettre de transmettre n'importe quelle liste d'une famille de types de liste associés et garantir toujours que je peux écrire une valeur d'un type T spécifique à cette liste. Mais il ne peut pas être garanti de lire les valeurs de type T spécifique si je lis dans la liste.
Alors maintenant, grâce aux jokers génériques, je peux faire n'importe lequel de ces appels avec cette seule méthode:
// 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());
Considérez ce code déroutant et très large pour exercer votre cerveau. Les lignes commentées sont illégales et la raison pour laquelle est indiquée à l'extrême droite de la ligne (besoin de faire défiler pour voir certaines d'entre elles):
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>
cela ne signifie pas "liste d'objets de différents types, qui s'étendent tousNumber
". Cela signifie "liste d'objets d'un seul type qui s'étendNumber
".