2014-06-19 2 views
11

Pour l'échantillon de code suivant:Java Generics: affectation avec des paramètres génériques imbriqués

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 
} 

lignes 1, 3 et 4 ne compile 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>>>) 

lignes 2 et 5, cependant, la compilation.

Quelqu'un peut-il expliquer pourquoi les lignes 1, 3 et 4 ne sont pas des attributions légales? Et si les paramètres génériques ne peuvent pas être utilisés de cette façon sur ces lignes, alors pourquoi l'affectation sur la ligne 2 est-elle légale?

+0

Très bonne question! Pour * ligne 1 *, c'est parce que vous ne pouvez rien ajouter à une liste de type inconnu sauf 'null'. – rlegendi

Répondre

7

listOne.add(abcdef) (ligne 1) est invalide car List<?> représente une liste d'un type spécifique inconnu. Par exemple, il pourrait s'agir d'un List<String>, donc nous ne voudrions pas ajouter quoi que ce soit qui ne soit pas String. L'erreur du compilateur se produit car Abc<Def<Ghi<String>>> n'est pas assignable à ?.

listTwo.add(abcdef) (ligne 2) est valide parce que List<Abc<?>> représente une liste de Abc s de tout type. C'est vrai - imbriqué Les caractères génériques sont différents des caractères génériques de premier niveau en ce sens qu'ils représentent tout type plutôt qu'un type spécifique (en d'autres termes, les caractères génériques imbriqués ne sont pas capture). Le compilateur le permet car Abc<Def<Ghi<String>>> est assignable à Abc<?>. Voir ce poste pour poursuivre la discussion des wildcards imbriquées: Multiple wildcards on a generic methods makes Java compiler (and me!) very confused

listThree.add(abcdef) (ligne 3) est invalide parce List<Abc<Def<?>>> représente une liste de Abc s de Def s de tout type. Les génériques ne sont pas covariants, donc Abc<Def<Ghi<String>>> n'est pas assignable à Abc<Def<?>>, même si Def<Ghi<String>> est affectable à Def<?>. Un List<Integer> n'est pas assignable à un List<Number> pour la même raison. Voir cet article pour plus d'explications: Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

listFour.add(abcdef) (ligne 4) est invalide pour la même raison - Abc<Def<Ghi<String>>> est incessible à Abc<Def<Ghi<?>>>.

listFive.add(abcdef) (ligne 5) est valide car les types génériques correspondent exactement - Abc<Def<Ghi<String>>> est évidemment assignable à Abc<Def<Ghi<String>>>.

+3

A voulu faire un suivi pour noter que les problèmes d'assignabilité des lignes 3 et 4 peuvent être résolus en changeant les déclarations de 'List >> listThree' à' List >> listThree' et de 'List >>>'' Liste >>> listFour'. Merci pour l'explication concise et les liens utiles; c'est beaucoup plus clair maintenant. – Sumitsu