Comment convertir un iterator d’une classe en un iterator d’une sous-classe?

J’ai essayé de lancer un iterator d’une classe sur un iterator d’une sous-classe de ladite classe. Cela m’a donné une erreur “types inconvertibles”. Pourquoi n’est-ce pas possible et quel est le moyen le plus élégant de contourner le problème? (Ou encore, pourquoi est-ce une mauvaise idée si c’est le cas?)

Utiliser une boucle for-each n’est pas une solution dans ce cas: j’essaie d’implémenter iterator() et le moyen le plus simple de le faire est de renvoyer le iterator() de l’un des champs de ma classe, mais celui-ci ne ne pas avoir le type exact requirejs. Je ne peux pas changer la signature de mon iterator() non plus.

 public interface SomeoneElsesInterface { public Iterator iterator(); } public abstract class MyAbstractClass implements SomeoneElsesInterface { final MyAbstractClass[] things; public MyAbstractClass(SomeoneElsesInterface... things) { this.things = (MyAbstractClass[]) things; } } public class MyClass extends MyAbstractClass { public MyClass(MyAbstractClass thing1, MyAbstractClass thing2) { super(thing1, thing2); } public Iterator() { return (Iterator) Arrays.asList(things).iterator(); } } 

Je pourrais bien sûr changer le type de things . Cependant, il me faudrait beaucoup de moulages ailleurs. Je sais que mon constructeur ne sera pas appelé avec des objects qui ne sont pas MyAbstractClass s mais je ne peux pas changer l’interface de toute façon.

Cela semble être aussi simple que d’utiliser une spécification d’argument de type explicite :

 public class MyClass extends MyAbstractClass { // ... public Iterator iterator() { return Arrays.asList(things).iterator(); } } 

Le problème est que Arrays#asList() que vous voulez une liste de type List , qui générera un iterator de type Iterator . Le paramètre de type d’ Iterator n’étant pas covariant , vous ne pouvez pas fournir d’ Iterator lorsqu’un Iterator est requirejs. En forçant Arrays#asList() à créer une liste de type List , comme indiqué ci-dessus, vous obtenez également le type d’iterator prévu qui revient de votre appel à Iterable#iterator() .

L’auteur de SomeoneElsesInterface aurait été plus gentil de spécifier le type de retour de sa méthode iterator() comme Iterator Iterator .

Je pense que d’après votre question, vous essayez de faire quelque chose comme ceci:

 Iterator original = ... Iterator converted = (Iterator)original; 

Est-ce exact?

Si c’est le cas, c’est malheureusement impossible. Le problème est que l’ original peut contenir des objects qui ne sont pas des Ssortingng , ce qui permettrait de briser le contrat générique, c’est-à-dire que la converted pourrait contenir quelque chose qui ne soit pas une Ssortingng .

Je ne pense pas qu’il existe une solution de contournement élégante pour cela.

Vous dites que le moyen le plus simple d’implémenter iterator() est de renvoyer l’iterator d’un champ d’instance. Je suppose donc que vous avez quelque chose comme ceci:

 class IterableThing implements Iterable { private Collection someStuff; public Iterator iterator() { return (Iterator)someStuff.iterator(); } } class Bar { } class Foo extends Bar { } 

S’il est possible de garantir que someStuff ne contient que des occurrences de Foo , pouvez-vous alors déclarer que someStuff d’entre elles sont une Collection plutôt qu’une Collection someStuff ? Si ce n’est pas le cas, il n’a pas vraiment de sens de simplement renvoyer l’iterator de someStuff , car il peut contenir quelque chose qui n’est pas un Foo .

Je suppose que vous devez réfléchir aux garanties que vous pouvez réellement offrir. Si vous ne pouvez pas garantir que someStuff contient uniquement des someStuff Foo vous devrez probablement conserver votre propre état ou filtrer le contenu de someStuff à la demande.

EDIT: Vous avez mis à jour votre question avec le code. Impressionnant.

Il semble donc que vous essayez réellement de renvoyer un iterator sur la super-classe du type. Cela rend les choses beaucoup plus faciles.

Dans votre cas particulier, vous pouvez probablement le résoudre avec ceci:

 return Arrays.asList(things).iterator(); 

Cela générera des avertissements, mais ce n’est pas grave, car vous savez que vous avez garanti la sécurité du type.

Utilisez for-each boucle au lieu d’ Iterator .

for-each été introduit à partir de Java 1.5

Voir ce lien pour plus de détails:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html

Que faire si vous changez Arrays.asList(things) en Arrays.asList((SomeoneElsesInterface[]) things) ? Une fois que le tableau est converti dans le bon type, List et Iterator doivent suivre.

Exemple de Java pour chacun (complément de la réponse Kumar):

 List ssortingngs = new ArrayList(); ssortingngs.add( "one" ); ssortingngs.add( "two" ); ssortingngs.add( "three" ); for ( Ssortingng item : ssortingngs ) { System.out.println( item ); }