Wie wird ein Iterator einer Klasse in einen Iterator einer Unterklasse umgewandelt?

8

Ich habe versucht, einen Iterator einer Klasse auf einen Iterator einer Unterklasse der Klasse zu übertragen. Dies gab mir einen Fehler "inconvertible types". Warum ist das nicht möglich und was ist der eleganteste Weg, um es zu umgehen? (Oder alternativ, warum ist es eine schlechte Idee, wenn es ist?)

Die Verwendung einer for-each-Schleife ist in diesem Fall keine Lösung: Ich versuche, iterator() zu implementieren, und die einfachste Möglichkeit wäre, die iterator() eines der Felder meiner Klasse zurückzugeben dieser hat nicht den genau erforderlichen Typ. Ich kann die Signatur meines iterator() auch nicht ändern.

%Vor%

Ich könnte natürlich nur den Typ von things ändern. Allerdings würde ich in diesem Fall an anderen Stellen sehr viel Gips benötigen. Ich weiß, dass mein Konstruktor nicht mit Objekten aufgerufen wird, die nicht MyAbstractClass s sind, aber ich kann die Schnittstelle trotzdem nicht ändern.

    
Erik 15.07.2012, 17:07
quelle

5 Antworten

4

Das sieht so einfach aus wie explizit Typargumentspezifikation :

%Vor%

Das Problem ist, dass Arrays#asList() folgert, dass Sie eine Liste vom Typ List<MyAbstractClass> wollen, die einen Iterator vom Typ Iterator<MyAbstractClass> ergibt. Da der Typparameter Iterator nicht kovariant ist, können Sie kein Iterator<MyAbstractClass> angeben, für das ein Iterator<SomeoneElsesInterface> erforderlich ist. Indem Sie Arrays#asList() zwingen, eine Liste vom Typ List<SomeoneElsesInterface> zu erstellen, wie oben gezeigt, werden Sie auch mit dem beabsichtigten Iterator-Typ fertig, der von Ihrem Aufruf an Iterable#iterator() zurückkommt.

Der Autor von SomeoneElsesInterface hätte es besser gefunden, den Rückgabetyp seiner iterator() -Methode als Iterator<? extends SomeoneElsesInterface> anzugeben.

    
seh 15.07.2012, 17:48
quelle
5

Ich denke, dass du aus deiner Frage versuchst, so etwas zu tun:

%Vor%

Stimmt das?

Wenn ja, ist das leider unmöglich. Das Problem besteht darin, dass original Objekte enthalten kann, die nicht String s sind, so dass dieser Cast den Generics-Vertrag bricht, d. H.% Co_de% könnte etwas enthalten, das kein converted ist.

Ich denke nicht, dass es einen eleganten Workaround dafür gibt.

Sie sagen, der einfachste Weg, String zu implementieren, besteht darin, den Iterator eines Instanzfeldes zurückzugeben. Ich nehme an, Sie haben so etwas:

%Vor%

Wenn iterator() garantiert nur Instanzen von someStuff enthalten kann, können Sie dann Foo als someStuff und nicht als Collection<Foo> deklarieren? Wenn nicht, dann ist es nicht wirklich sinnvoll, den Iterator von Collection<Bar> nur zurückzugeben, weil er etwas enthält, das kein someStuff ist.

Ich denke, Sie müssen darüber nachdenken, was Sie tatsächlich leisten können. Wenn Sie nicht garantieren können, dass Foo nur someStuff s enthält, müssen Sie wahrscheinlich Ihren eigenen Status beibehalten oder den Inhalt von Foo bei Bedarf filtern.

EDIT: Sie haben Ihre Frage mit Code aktualisiert. Super.

Es sieht also so aus, als würden Sie versuchen, einen Iterator über die Superklasse dieses Typs zurückzugeben. Das macht die Dinge viel einfacher.

In Ihrem speziellen Fall können Sie wahrscheinlich damit umgehen:

%Vor%

Es werden einige Warnungen generiert, aber das ist in Ordnung, weil Sie wissen, dass Sie die Typensicherheit garantiert haben.

    
Cameron Skinner 15.07.2012 17:26
quelle
1

Verwenden Sie for-each loop anstelle von Iterator .

for-each wurde von Java 1.5

eingeführt

Siehe diesen Link für weitere Details:

Ссылка

    
Kumar Vivek Mitra 15.07.2012 17:09
quelle
0

Was passiert, wenn Sie Arrays.asList(things) in Arrays.asList((SomeoneElsesInterface[]) things) ändern? Sobald das Array in den richtigen Typ umgewandelt wurde, sollten die Liste und der Iterator folgen.

    
Alan Stokes 15.07.2012 17:36
quelle
-1

Beispiel für Java for-each (Ergänzung der Kumar-Antwort):

%Vor%     
davidbuzatto 15.07.2012 17:11
quelle

Tags und Links