为什么java Iterable接口不能使用泛型通配符?或者:为什么我不能重写iterator()方法返回子类的Iterator?

use*_*411 4 java generics overriding iterable

我有一些类:SearchResponse,SearchResponseHit,SpecialSearchResponse(扩展SearchResponse)和SpecialSearchResponseHit(扩展SearchResponseHit).

SearchResponse看起来像这样:

public class SearchResponse implements Iterable<SearchResponseHit> {

    [...]

    public Iterator<SearchResponseHit> iterator() {
        return searchResponseHits.iterator();
    }
}
Run Code Online (Sandbox Code Playgroud)

这使我可以在foreach循环中使用SearchResponse的实例,如下所示:

for (SearchResponseHit hit : mySearchResponse) {
    [...]
}
Run Code Online (Sandbox Code Playgroud)

现在,当我有一个SpecialSearchResponse实例时,我想做的,但无法弄清楚如何编译这段代码:

for (SpecialSearchResponseHit specialHit : mySpecialSearchResponse) {
    [...]
}
Run Code Online (Sandbox Code Playgroud)

这给了我以下编译器错误:

Type mismatch: cannot convert from element type SearchResponseHit to SpecialSearchResponseHit
Run Code Online (Sandbox Code Playgroud)

如果我尝试将此代码添加到SpecialSearchResponse:

public Iterator<SpecialSearchResponseHit> iterator() {
    [...]
}
Run Code Online (Sandbox Code Playgroud)

......我收到错误:

The return type is incompatible with Iterable<SearchResponseHit>.iterator()
Run Code Online (Sandbox Code Playgroud)

我尝试将SearchResponse中的方法更改为:

    public Iterator<? extends SearchResponseHit> iterator() {
        return searchResponseHits.iterator();
    }
Run Code Online (Sandbox Code Playgroud)

......但这给了我错误:

The return type is incompatible with Iterable<SearchResponseHit>.iterator()
Run Code Online (Sandbox Code Playgroud)

然后我尝试将类定义更改为:

public class SearchResponse implements Iterable<? extends SearchResponseHit>
Run Code Online (Sandbox Code Playgroud)

...但这给了我这个错误:

    The type SearchResponse cannot extend or implement Iterable<? extends SearchResponseHit>. A supertype may not specify any wildcard
Run Code Online (Sandbox Code Playgroud)

解决这个问题的最好(也是最漂亮)的方法是什么?或者我是否必须跳过foreach方法(以及在幕后使用Iterable接口的其他函数)并编写getSpecialIterator()方法然后直接使用迭代器?

问候/ J.

ass*_*ias 9

一种方法是以下列方式声明各种类:

public class SearchResponse<T  extends SearchResponseHit> implements Iterable<T> {
    List<T> searchResponseHits;

    public Iterator<T> iterator() {
        return searchResponseHits.iterator();
    }
}

public class SearchResponseHit {}

public class SpecialSearchResponse extends SearchResponse<SpecialSearchResponseHit> {}
public class SpecialSearchResponseHit extends SearchResponseHit {}
Run Code Online (Sandbox Code Playgroud)

这样你可以像这样调用它们:

    SearchResponse<SearchResponseHit> sr = new SearchResponse<SearchResponseHit>();
    for (SearchResponseHit h : sr) {}

    SpecialSearchResponse ssr = new SpecialSearchResponse();
    for (SpecialSearchResponseHit h : ssr) {}
Run Code Online (Sandbox Code Playgroud)

但是这会在SearchResponse课堂上引入泛型,你不能简单地声明SearchResponse sr = new SearchResponse()(没有警告和演员表).


更新
在您的评论之后,您可以创建一个包含泛型样板的公共超类 - 您可以将其设为抽象并打包私有,以便您的类的用户看不到它:

abstract class AbstractSearchResponse<T  extends SearchResponseHit> implements Iterable<T>{
    List<T> searchResponseHits;

    public Iterator<T> iterator() {
        return searchResponseHits.iterator();
    }
}

public class SearchResponse extends AbstractSearchResponse<SearchResponseHit> { }
public class SpecialSearchResponse extends AbstractSearchResponse<SpecialSearchResponseHit> {}
Run Code Online (Sandbox Code Playgroud)

现在您可以根据需要调用2个孩子:

SearchResponse sr = new SearchResponse();
for (SearchResponseHit h : sr) {}

SpecialSearchResponse ssr = new SpecialSearchResponse();
for (SpecialSearchResponseHit h : ssr) {}
Run Code Online (Sandbox Code Playgroud)