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?

Author: sumitsu, 2014-06-19

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 Abcs 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 Abcs Defs 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 est-il une sous-classe de List? Pourquoi les génériques de Java ne sont-ils pas implicitement polymorphes?

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>>>.

 7
Author: Paul Bellora, 2017-05-23 11:44:41