web-dev-qa-db-fra.com

Liste <? étend MyType>

J'ai une Java question sur les génériques. J'ai déclaré une liste générique:

List<? extends MyType> listOfMyType;

Ensuite, dans une méthode, j'essaie d'instancier et d'ajouter des éléments à cette liste:

listOfMyType = new ArrayList<MyType>();
listOfMyType.add(myTypeInstance); 

myTypeInstance n'est qu'un objet de type MyType; il ne compilera pas. Ça dit:

La méthode add (capture # 3-of? Étend MyType) dans le type List <capture # 3-of? étend MyType> n'est pas applicable pour les arguments (MyType)

Une idée?

39
Lancelot

Vous ne pouvez pas faire de "put" avec extend. Regardez Generics - Get and Put rule .

32
Surya

Considérer:

class MySubType extends MyType {
}

List<MySubType> subtypeList = new ArrayList<MySubType>();
List<? extends MyType> list = subtypeList;
list.add(new MyType());
MySubType sub = subtypeList.get(0);

sub contient maintenant un MyType ce qui est très faux.

26

Vous ne devriez pas avoir besoin d'utiliser la syntaxe de capture générique dans votre cas, déclarant simplement

List<MyType> listOfMytype;

cela devrait suffire. Si vous voulez savoir exactement pourquoi, le Java Generics Tutorial a plus que vous ne voudriez jamais savoir sur la folie ésotérique de Java Generics. La page 20 s'adresse à votre spécifique Cas.

Quant à savoir pourquoi l'ajout avec la capture générique ne fonctionne pas, c'est parce que le compilateur ne peut pas déterminer exactement quelle sous-classe de MyType la liste sera dans tous les cas, donc le compilateur émet une erreur.

6
Cameron Pope

Il y a un fil similaire ici: Comment les éléments peuvent-ils être ajoutés à une collection générique générique?

Pour avoir une idée du fonctionnement des génériques, consultez cet exemple:

    List<SubFoo> sfoo = new ArrayList<SubFoo>();
    List<Foo> foo;
    List<? extends Foo> tmp;

    tmp = sfoo;
    foo = (List<Foo>) tmp;

Le truc, c'est que cela n'a pas été conçu pour les variables locales/membres, mais pour les signatures de fonction, c'est pourquoi c'est tellement à l'envers.

3
zslevi

Je ne sais pas si cela vous aidera vraiment, mais c'est quelque chose que j'ai dû utiliser lors de l'appel d'une méthode générique de Spring Framework et en souhaitant également renvoyer une liste générique:

public <T> List<T> findAll(String tableName,Class<?> table) {
    String sql = "SELECT * FROM "+ tableName ;
    List<?> entities = getSimpleJdbcTemplate().query(sql,
            ParameterizedBeanPropertyRowMapper.newInstance(table));
            return (List<T>) entities;
}

Semble que la paramétrisation a besoin de vous pour utiliser le? connectez-vous à la liste pour recevoir les résultats, puis convertissez la liste en type de retour attendu.

Je suis toujours ébloui par les génériques ...

2
will824