我有一些类:SearchResponse,SearchResponseHit,SpecialSearchResponse(extends 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
答案 0 :(得分: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> {}
现在你可以按照自己的意愿打电话给两个孩子:
SearchResponse sr = new SearchResponse();
for (SearchResponseHit h : sr) {}
SpecialSearchResponse ssr = new SpecialSearchResponse();
for (SpecialSearchResponseHit h : ssr) {}
答案 1 :(得分:0)
公认的答案有很好的解决方法,但是首先要说明为什么这是一个问题,这是因为Iterable的定义不明确。迭代器方法的签名应为Iterator<? extends T> iterator()
。由于Iterator<T>
的所有方法仅以协变方式使用类型参数T,因此Iterator<T>
等效于Iterator<? extends T>
,但通配符版本更加灵活。反对这样做的唯一论据是,如果您认为将来会添加T的反用法(例如insert(T obj)
)。但是,这样做可能仍然需要一个新的界面。