我正在开发一个流畅的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<Apple>
返回一个Apple
的实例,而不是像execute()
那样返回一个Query<Apple>
的实例? - Pyranja