Reputation: 12742
In the following code:
public class Bar { ... }
public class Foo extends Bar { ... }
public class BarIterable implements Iterable<Bar> {
List<Foo> foos = ...
@Override
public Iterator<Bar> iterator() {
return foos.iterator(); // Error: Type mismatch ...
}
}
I get an error at the indicated position since foos.iterator()
returns an Iterable<Foo>
rather than an Iterable<Bar>
. Unfortunately, a simple cast won't work:
return (Iterator<Bar>) foos.iterator(); // Error: Cannot cast ...
Java also doesn't allow me to change the definition of BarIterable
to
public class BarIterable implements Iterable<? extends Bar> { ... // Error: A supertype may not specify any wildcard
What's a good way to resolve this problem that does not involve implementing Iterable<Foo>
instead (the Iterable-implementation comes from another interface that doesn't know about Foo)?
Do I have to write myself a wrapper Iterator-class that "unpacks" each value?
Upvotes: 4
Views: 266
Reputation: 279920
Since Foo
is a subtype of Bar
, you could just cast the List
.
return ((List<Bar>)(List<? extends Bar>) foos).iterator();
and suppress the warnings.
Edit by Markus A.:
Or, you can cast the iterator directly using the intermediate-cast-trick:
return (Iterator<Bar>)(Iterator<? extends Bar>) foos.iterator();
End edit
With Java 8, you can stream over the elements and construct a new List
of type Bar
.
@Override
public Iterator<Bar> iterator() {
return foos.stream().<Bar>map((foo) -> foo /* considered a Bar */).collect(Collectors.toList()).iterator();
}
but you're doing a lot of intermediate operations just to view the List
from a super type's point of view.
Upvotes: 6