3 votes

problème de moulage des génériques d'interface java

La méthode add(capture#2-of ? extends IObject) dans le type List n'est pas applicable pour les arguments (IDerived)

protected List<? extends IObject> getObjects()
{
    List<? extends IObject> objects = new ArrayList<IObject>();
    for (String id: item_ids)
    {
        IDerived object = (IDerived) readObject(id);
        objects.add(object); #error
    }
    return objects;
}

interface IDerived extends interface IVersionedObject extends interface IObject

Si je change le type des objets en Liste, l'erreur disparaît, ce qui n'a aucun sens car il faut effectuer exactement le même cast vers le type de retour de la fonction.

7voto

Costi Ciudatu Points 13020

Essayez ça :

protected <T extends IObject> List<T> getObjects() {
    List<T> objects = new ArrayList<T>();
    for (String id: item_ids)
    {
        T object = (T) readObject(id);
        objects.add(object); // NO error
    }
    return objects;
}

EDIT (brève explication) :

De cette façon, votre méthode fonctionnera parfaitement avec n'importe quel sous-type de IObject (les listes et les castings à l'intérieur deviennent génériques) et le type de retour sera déduit des attentes de l'appelant (comme vous l'aviez apparemment prévu).

En réponse au commentaire, vous pouvez désormais appeler la méthode getObjects() de la manière suivante :

// This should only be used if readObject() behaves like
// getObjects() and is able to return any requested subtype.
// Otherwise, you'll get a ClassCastException when trying to get
// something from the derivedList in case readObject() put something
// else there (which is not a subtype of IDerived).
List<IDerived> derivedList = getObjects();

// This is the safe way to go in case you don't have
// full control over what readObject() returns.
// But if you're using it like this (all the time), you'd better
// return List<IObject> from getObjects() and get rid
// of generics.
List<? extends IObject> objectList1 = getObjects();
List<IObject> objectList2 = getObjects();

4voto

Andrew White Points 23508

Je ne sais pas si je vais expliquer ça correctement, mais je vais le faire.

List<? extends IObject> objects = new ArrayList<IObject>();

Indique que la liste est d'un type inconnu qui étend IObject. Même si vous mettez un new ArrayList<IObject>(); sur la rhs, le type générique de la liste n'est toujours pas défini de façon précise. En d'autres termes, le type générique n'est pas "intégré" lorsque vous lui attribuez une référence.

Donc, quand vous appelez objects.add(object); Le vérificateur de type ne sait pas si la liste sera compatible avec IDerived car la liste pourrait être de type IVersionedObjectSomethingElse . Même si c'est impossible à partir de votre flux logique, il est possible de le construire.

List<? extends IObject> objects = null;
if (test) { 
    objects = new ArrayList<IObject>();
}
else {
    objects = new ArrayList<IVersionedObject2>();
}

objects.add( (IDerived) iDerivedObj ); // iDerived *might* not be compatible

-1voto

Ray Points 2879

Pourquoi les jokers ? Au lieu de ? extends IObject utiliser IDerived

Changez cette ligne

List<? extends IObject> objects = new ArrayList<IObject>();

à ça :

List<IDerived> objects = new ArrayList<IDerived>();

Et le changement

protected List<? extends IObject> getObjects()

à

protected List<IDerived> getObjects()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X