简体   繁体   中英

Implementing Iterable by returning an Iterator over a sub-type

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM