2010-07-22 8 views
2

Tentative de génériques-si un code hérité, je suis coincé. J'ai un parentObject qui encapsule un objet ChildObject pour fournir des opérations de type groupe sur ChildObject. Le plus utilement, il permet l'itération sur la collection d'objets enfants. Lorsque j'essaie d'ajouter des génériques au mixage, je n'arrive pas à le rendre convivial avec la méthode itérateur sans une erreur de "naming clash", ou dans l'exemple ci-dessous, un "Le type de retour est incompatible avec l'erreur Iterable.iterator() ". Des suggestions? (Question bonus - est-il une meilleure façon d'écrire la méthode thegetChildObjectByIndex d'éviter() pour éviter d'avertissement autre que complier d'effacement de type supprimer les avertissements?) Merci beaucoup à l'avance pour toute aideProblème de génériques Java

public class ParentObject implements Iterable<ChildObject> { 
    protected List<? super ChildObject> theChildObjects; 

    @SuppressWarnings("unchecked") 
    public <T extends ChildObject> T getChildObjectByIndex(int idx) { 
     return (T)theChildObjects.get(idx); 
    } 

    public Iterator<? super ChildObject> iterator() { 
     return java.util.Collections.unmodifiableCollection(this.theChildObjects).iterator(); 
    } 

} 
+2

Sont ces '? super' et 'T s'étend' absolument nécessaire? Sinon, supprimez-les. Sinon, mettez à jour votre question pour clarifier l'exigence de conception fonctionnelle à propos de ces nécessités plus. Alors seulement, nous pouvons suggérer les meilleures généra- tions appropriées. – BalusC

+0

De votre description, je suis prêt à parier que «super» ne signifie pas ce que vous pensez que cela signifie. –

+0

Vous auriez gagné ce pari, mais pas plus ... – Chris

Répondre

3

Si ParentObjet ne contient un sous-type de ChildObject, vous pouvez paramètrer ParentObjet sur ce type:

public class ParentObject<T extends ChildObject> implements Iterable<T> { 
    protected List<T> theChildObjects; 

    public T getChildObjectByIndex(int idx) { 
     return theChildObjects.get(idx); 
    } 

    public Iterator<T> iterator() { 
     return java.util.Collections.unmodifiableCollection(this.theChildObjects).iterator(); 
    } 
} 
+0

Voilà la réponse! Pour ma première expérience avec des classes génériques, mon erreur n'était pas de comprendre que vous définissiez le type générique au niveau de la classe juste une fois. J'avais commencé sur la liste et travaillé vers le haut, devenant totalement confus. – Chris

0

on dirait que dans votre exemple ParentObjet est une sorte de classe de conteneur qui n'a vraiment aucun rapport avec ChildObject. Est-ce que ChildObject étend ParentObject? Si oui, cela semble moins qu'idéale. Il semble aussi que vous devriez utiliser "extend" dans les génériques au lieu de super, à moins que je ne comprenne pas ce que vous essayez de faire. Qu'en est-il de ce qui suit? Ou est-ce trop simple pour ce que vous voulez faire?

public class WidgetContainer<T> implements Iterable<T> { 
    protected List<T> theWidgets; 

    public T getWidgetByIndex(int idx) { 
     return theWidgets.get(idx); 
    } 

    public Iterator<T> iterator() { 
     return Collections.unmodifiableCollection(theWidgets).iterator(); 
    } 
} 

WidgetContainer<SomeWidget> myWidgetContainer = new WidgetContainer<SomeWidget>(); 

Aussi je pourrais mettre en cache une copie de la collection et non modifiable utiliser chaque fois que vous avez besoin d'un iterator au lieu de construire une à la volée.

+0

En ce qui concerne la mise en cache de la collection non modifiable - tout ce que Collections.unmodifiableCollection() fait est un pointeur vers l'objet original en mémoire, mais qui renvoie une exception non prise en charge lorsque vous appelez l'une des méthodes de collecte mutantes. L'objet de collection n'est pas cloné ou copié, il s'agit donc d'une opération intrinsèquement bon marché. Comme ma liste est modifiable, je pense que le coût de la gestion de la copie mise en cache pour la garder synchronisée serait plus élevé que celui d'une nouvelle collection non modifiable à chaque fois. Des pensées? – Chris

+0

Je crois comprendre que les méthodes Collections. * Renvoient de nouvelles collections qui * enveloppent * la collection originale, en lançant des exceptions toutes les opérations de mutation et en déléguant le reste à la collection originale. Si c'est le cas, vous créez essentiellement une nouvelle classe wrapper chaque fois que quelqu'un appelle votre méthode iterator(). Si vous allez muter la collection, je vous suggère de stocker deux copies: la version originale non enveloppée que vous utiliseriez lorsque vous deviez la changer, et la version immuable enveloppée que vous utiliseriez à chaque fois vous devez repasser un itérateur. – jph

+0

Remarque: il peut être plus simple de faire en sorte que votre classe de conteneur étende l'une des classes de collections, comme ArrayList, puis remplace les méthodes que vous souhaitez modifier (par exemple, itérateur). Votre classe pourrait stocker une "version" immuable de lui-même en interne à utiliser chaque fois qu'elle a besoin de repasser un itérateur immuable. Étant donné que le wrapper immutable est soutenu par la collection d'origine, il reflète toutes les modifications apportées à l'original. – jph