【发布时间】:2013-05-14 21:28:32
【问题描述】:
我正在开发一个流畅的 API,并试图利用 Java 的通用方法来提供一个优雅的 API,为我的用户处理类型转换。由于类型擦除,我在让它工作时遇到了一些麻烦。
这是我的界面的简化版本,显示了我遇到的问题:
interface Query<T extends Query<T>> {
T execute();
Query<T> appendClause();
}
interface A<T extends A> extends Query<T> { }
class AImpl implements A<A> {
A execute() { ... }
Query<A> appendClause() { ... }
}
AImpl.appendClause() 出现错误。编译器说A 不在其范围内,应该扩展Query。据我所知,我声明AImpl 实现A<A> 意味着A 确实 扩展Query<A>。
按照此处的另一个答案,我尝试通过将AImpl 更改为:
class AImpl implements A<AImpl> {
AImpl execute() { ... }
Query<AImpl> appendClause() { ... }
}
现在我在编译 A 时遇到错误,提示“类型参数 T 不在其范围内”。
有人对如何处理这个问题有任何建议吗? Java 的泛型让我头疼。
编辑
我已将 A 的定义更改为
interface A<T extends A<T>> extends Query<T> { }
这让 AImpl 的第二个实现开始工作了。但我还想扩展 API,使其能够查询 A 的子类:
interface B<T extends B> extends A<B> { }
class BImpl implements B<BImpl> {
BImpl execute() { ... }
Query<BImpl> appendClause() { ... }
}
这个定义让我在B 的声明中出错:“类型参数 B 不在其范围内;应该扩展 A”。
我可以通过将 B 更改为来清除该错误
interface B<T extends B<T>> extends A<B<T>> { }
但是现在我的接口定义开始看起来很荒谬,我觉得我做错了什么。另外,我仍然在 BImpl 中遇到错误:“BImpl 中的 appendClause() 无法在 Query 中实现 appendClause();尝试使用不兼容的返回类型”。
关于如何清理我的子类定义以便我不需要在 extends 中指定整个继承层次结构或如何让 BImpl 工作的任何建议?
编辑 2
好的,我遇到了另一个问题。我有一个生成查询的工厂类:
public class QueryFactory {
public static <T extends Query<T>> Query<T> queryForType(Class<T> type) { ... }
}
和客户端代码:
Query<B> bQuery = QueryFactory.queryForType(B.class);
我的客户端代码在 bQuery 的声明中给了我一个错误:“类型参数 'B' 不在其范围内;应该扩展 'Query'”。在这一点上,我认为 B 确实扩展了 Query...
如果我将 queryForType() 调用更改为
,此错误就会消失Query<? extends B> bQuery = QueryFactory.queryForType(B.class);
但我仍然收到来自编译器的未经检查的警告:
unchecked method invocation: <T>queryForType(Class<T>) in QueryFactory is applied to Class<B>
unchecked conversion found: Query required: Query<B>
看起来类型擦除再次与我作斗争,但我不明白这些警告。还有什么建议可以让我重回正轨吗?谢谢!
编辑 3
如果我将客户端代码更改为
,我可以在没有警告的情况下编译它Query<BImpl> bQuery = QueryFactory.queryForType(BImpl.class);
但我真的很想对 API 用户隐藏实现类。我尝试将 B 设为抽象类而不是接口,以防问题与此有关,但没有帮助。
【问题讨论】:
-
Query
> 类型应该代表什么?我认为签名没有意义。例如我希望 Query<Apple>返回Apple的实例,而不是execute()的Query<Apple>实例? -
Apple 扩展了 Query
。在这种情况下,execute() 返回一个 Apple,您可以在 Apple 上调用 appendClause() 来查找更具体的 Apple。 -
让您阅读这篇文章了吗unquietcode.com/blog/2011/programming/…
-
感谢@Greg 的解释。为一个有趣的问题 +1。
标签: java generics fluent-interface