Génériques Java: affectation avec des paramètres génériques imbriqués
Pour l'exemple de code suivant:
public static class Abc<X> { }
public static class Def<Y> { }
public static class Ghi<Z> { }
public void doThis() {
List<?> listOne;
List<Abc<?>> listTwo;
List<Abc<Def<?>>> listThree;
List<Abc<Def<Ghi<?>>>> listFour;
List<Abc<Def<Ghi<String>>>> listFive;
Abc<Def<Ghi<String>>> abcdef;
abcdef = new Abc<Def<Ghi<String>>>();
listOne.add(abcdef); // line 1
listTwo.add(abcdef); // line 2
listThree.add(abcdef); // line 3
listFour.add(abcdef); // line 4
listFive.add(abcdef); // line 5
}
Les lignes 1, 3 et 4 ne compilent pas:
(ligne 1)
The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
(ligne 3)
The method add(Abc<Def<?>>) in the type List<Abc<Def<?>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
(ligne 4)
The method add(Abc<Def<Ghi<?>>>) in the type List<Abc<Def<Ghi<?>>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
Les lignes 2 et 5, cependant, compilent.
Quelqu'un Pourrait-il expliquer pourquoi les lignes 1, 3 et 4 ne sont pas des affectations? Et si les paramètres génériques ne peuvent pas être utilisés de cette manière sur ces lignes, alors pourquoi l'affectation sur la ligne 2 est-elle légale?
1 answers
listOne.add(abcdef)
(ligne 1) n'est pas valide car List<?>
représente une liste de quelques inconnus type spécifique. Par exemple, il pourrait s'agir d'un List<String>
, donc nous ne voudrions rien ajouter qui ne soit pas un String
. L'erreur du compilateur se produit car Abc<Def<Ghi<String>>>
n'est pas assignable à ?
.
listTwo.add(abcdef)
(la ligne 2) est valide parce que List<Abc<?>>
représente une liste de Abc
s tout type. C'est vrai- les caractères génériques imbriqués sont différents des caractères génériques de niveau supérieur en ce qu'ils représentent n'importe quel type plutôt que certains type spécifique (en d'autres termes, les caractères génériques imbriqués ne le font pas capture). Le compilateur le permet car Abc<Def<Ghi<String>>>
est assignable à Abc<?>
. Voir cet article pour plus de détails sur les jokers imbriqués: Plusieurs jokers sur une méthode générique font un compilateur Java (et moi!) très confus
listThree.add(abcdef)
(ligne 3) n'est pas valide car List<Abc<Def<?>>>
représente une liste de Abc
s Def
s de tout type. Les génériques ne sont pas covariante, donc Abc<Def<Ghi<String>>>
n'est pas assignable à Abc<Def<?>>
, même si Def<Ghi<String>>
est assignable à Def<?>
. Un List<Integer>
n'est pas assignable à un List<Number>
pour la même raison. Voir cet article pour plus d'explications: List
listFour.add(abcdef)
(ligne 4) est invalide pour la même raison - Abc<Def<Ghi<String>>>
n'est pas assignable à Abc<Def<Ghi<?>>>
.
listFive.add(abcdef)
(ligne 5) est valide parce que les types génériques correspondent exactement - Abc<Def<Ghi<String>>>
est évidemment assignable à Abc<Def<Ghi<String>>>
.