4

我有一些类:SearchResponse、SearchResponseHit、SpecialSearchResponse(扩展 SearchResponse)和 SpecialSearchResponseHit(扩展 SearchResponseHit)。

SearchResponse 看起来像这样:

public class SearchResponse implements Iterable<SearchResponseHit> {

    [...]

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

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

for (SearchResponseHit hit : mySearchResponse) {
    [...]
}

现在,我想做但不知道怎么做,是在我有一个 SpecialSearchResponse 实例时编译这段代码:

for (SpecialSearchResponseHit specialHit : mySpecialSearchResponse) {
    [...]
}

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

Type mismatch: cannot convert from element type SearchResponseHit to SpecialSearchResponseHit

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

public Iterator<SpecialSearchResponseHit> iterator() {
    [...]
}

...我得到错误:

The return type is incompatible with Iterable<SearchResponseHit>.iterator()

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

    public Iterator<? extends SearchResponseHit> iterator() {
        return searchResponseHits.iterator();
    }

...但这给了我错误:

The return type is incompatible with Iterable<SearchResponseHit>.iterator()

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

public class SearchResponse implements Iterable<? extends SearchResponseHit>

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

    The type SearchResponse cannot extend or implement Iterable<? extends SearchResponseHit>. A supertype may not specify any wildcard

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

问候 /J

4

2 回答 2

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 {}

这样你就可以这样称呼他们:

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

    SpecialSearchResponse ssr = new SpecialSearchResponse();
    for (SpecialSearchResponseHit h : ssr) {}

但这在类中引入了泛型,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> {}

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

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

SpecialSearchResponse ssr = new SpecialSearchResponse();
for (SpecialSearchResponseHit h : ssr) {}
于 2012-06-07T14:51:09.793 回答
1

接受的答案有很好的解决方法,但至于为什么这是一个问题,这是因为 Iterable 定义不明确。迭代器方法的签名应该是Iterator<? extends T> iterator(). 由于所有的Iterator<T>'s 方法仅以协变的方式使用类型参数 T,Iterator<T>等价于Iterator<? extends T>,但通配符版本更灵活。反对这样做的唯一理由是,如果您认为将来会添加 T 的逆变用法(insert(T obj)例如)。但是,这样做可能无论如何都需要一个新界面。

于 2018-12-19T20:51:29.060 回答