Ne peut pas ajouter de la valeur à la Java collection avec des caractères génériques de type générique
Pourquoi ce code ne compile pas (Parent
est une interface)?
List<? extends Parent> list = ...
Parent p = factory.get(); //returns concrete implementation
list.set(0, p); //fails here: set(int, ? extends Parent) cannot be applied to (int, Parent)
Vous pourriez penser
List<? extends Parent>
est "une liste de choses qui s'étend Parent
", mais ce n'est pas réellement ce qu'il signifie. Il signifie "il existe un certain type de C
, tels que C
s'étend Parent
, et c'est une Liste de C
." Puisque nous ne savons pas ce que C
est, nous ne savons pas que l'un des Parents est un C
, de sorte que vous ne pouvez pas mettre un Parent
dans un List<C>
. C est appelé un type de capture.) Mais, vous pouvez en prendre une, parce que vous obtenez C
de la Liste, et C
est-un Parent
, donc c'est bien.OriginalL'auteur Sergey Mikhanov | 2010-09-15
Vous devez vous connecter pour publier un commentaire.
Il le fait pour des raisons de sécurité. Imaginez si cela a fonctionné:
Le sens de
List<? extends Parent>
est "Le est une liste d'un genre qui s'étendParent
. Nous ne savons pas quel type il pourrait être unList<Parent>
, unList<Child>
, ou unList<GrandChild>
." Que fait-il sûr de récupérer tous les éléments hors de laList<T>
de l'API et de convertirT
àParent
, mais il n'est pas sûr d'appel dans à laList<T>
API de conversion deParent
àT
... parce que la conversion peut être invalide.était dans la question, et suggère que
Child
est un exemple naturel d'une sous-classe. Pas les noms de classe j'aurais choisi à partir de zéro, mais suffisamment claire dans le contexte de la question.Ouais, je comprends, mais je pense qu'elle aurait été mieux si l'exemple ici utilise "Monoparentales" ou "NewParent" comme le sous-classe =)
Mais que faire si juste fait le "Parent" de la classe finale et a créé la liste: List<? s'étend Parent> parentList = new ArrayList<>(); (pas beaucoup de point, je sais, mais...) le compilateur ne pas savoir que les sous-classes de "Parent" ne peut pas exister et, par conséquent, être en mesure de déduire le runtime type de Liste? Si oui, pourquoi ne pas nous permettre d'ajouter un nouveau "Parent" de l'objet dans ce cas? (il peut garantir le type non?) Ce qui me manque?! Merci
Je ne m'attends pas que le travail, parce que je ne m'attends pas la langue des designers à l'envie de construire les règles dans le langage de spécification. Les génériques est déjà très difficile d'essayer d'ajouter des cas de coin à l'aide relativement à des situations inhabituelles est presque certainement pas en vaut la complexité.
OriginalL'auteur Jon Skeet
PECS - "Producteur - s'Étend du Consommateur, Super". Votre
List
est un consommateur deParent
objets.OriginalL'auteur Bozho
Voici ma compréhension.
Supposons que nous avons un type générique avec 2 méthodes
Supposons que nous avons un super type
P
, et il a des sous typesC1, C2 ... Cn
. (pour plus de commodité nous direP
est un sous-type de lui-même, et est en fait l'un desCi
)Maintenant nous avons aussi n types de béton
L<C1>, L<C2> ... L<Cn>
, comme si nous l'avons écrit manuellement n types:Nous n'avons pas eu à écrire manuellement eux, c'est le point. Il y a pas les relations entre ces types de
Pour C++ template, c'est la fin de l'histoire. Il s'agit essentiellement de la macro d'extension basé sur un "modèle" de la classe, il génère de nombreuses classes de béton, avec aucun type de relations entre eux.
Pour Java, il y a plus. Nous avons également obtenu un type de
L<? extends P>
, c'est un super type deL<Ci>
Ce genre de méthode doit exister dans
L<? extends P>
? Comme un super type, l'un de ses méthodes doivent être hornored par ses sous-types. Cette méthode devrait fonctionner:parce que, dans l'un quelconque de ses sous-type
L<Ci>
, il y a une méthodeCi get()
, qui est compatible avecP get()
- la méthode de remplacement a la même signature et covariants type de retour.Cela ne peut pas travailler pour
set()
bien que nous ne pouvons pas trouver un typeX
, de sorte quevoid set(X)
peut être remplacée parvoid set(Ci)
pour toutCi
. Doncset()
méthode n'existe pas dansL<? extends P>
.Il y a également un
L<? super P>
qui va dans l'autre sens. Il aset(P)
, mais pas deget()
. SiSi
est un super-type deP
,L<? super P>
est un super-type deL<Si>
.set(Si)
"remplace"set(P)
pas dans le sens habituel, mais le compilateur peut voir que pour être valable, toute invocation surset(P)
est valide invocation surset(Si)
OriginalL'auteur irreputable