Gre*_*reg 4 java generics fluent-interface
我正在开发一个流畅的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() { ... }
}
Run Code Online (Sandbox Code Playgroud)
我收到了错误AImpl.appendClause().编译器说它A不在其范围内,应该扩展Query.据我所知,我的声明,AImpl实现A<A>该方法A 不延长Query<A>.
在这里得到另一个答案后,我尝试通过更改AImpl为:分解任何潜在的无法解析的递归:
class AImpl implements A<AImpl> {
AImpl execute() { ... }
Query<AImpl> appendClause() { ... }
}
Run Code Online (Sandbox Code Playgroud)
现在我收到一个错误编译A,说"类型参数T不在其范围内".
有人对如何处理这个问题有任何建议吗?Java的泛型让我很头疼.
编辑
我把A的定义改为了
interface A<T extends A<T>> extends Query<T> { }
Run Code Online (Sandbox Code Playgroud)
这使得AImpl的第二个实现工作.但是我也希望扩展API以查询A的子类:
interface B<T extends B> extends A<B> { }
class BImpl implements B<BImpl> {
BImpl execute() { ... }
Query<BImpl> appendClause() { ... }
}
Run Code Online (Sandbox Code Playgroud)
这个定义在B声明中给我一个错误:"类型参数B不在其范围内;应该扩展A".
我可以通过将B更改为来清除该错误
interface B<T extends B<T>> extends A<B<T>> { }
Run Code Online (Sandbox Code Playgroud)
但现在我的界面定义开始看起来很荒谬,我觉得我做错了.另外,我在BImpl中仍然遇到错误:"BImpl中的appendClause()无法在Query中实现appendClause();尝试使用不兼容的返回类型".
关于如何清理我的子类定义的任何建议,所以我不需要指定整个继承层次结构extends或如何让BImpl工作?
编辑2
好的,我遇到了另一个问题.我有一个生成查询的工厂类:
public class QueryFactory {
public static <T extends Query<T>> Query<T> queryForType(Class<T> type) { ... }
}
Run Code Online (Sandbox Code Playgroud)
和客户代码:
Query<B> bQuery = QueryFactory.queryForType(B.class);
Run Code Online (Sandbox Code Playgroud)
我的客户端代码在bQuery的声明中给出了一个错误:"类型参数'B'不在其范围内;应该扩展'Query'".我认为在这一点上B确实扩展了Query ...
如果我将queryForType()调用更改为,则此错误消失
Query<? extends B> bQuery = QueryFactory.queryForType(B.class);
Run Code Online (Sandbox Code Playgroud)
但我仍然从编译器得到一个未经检查的警告:
unchecked method invocation: <T>queryForType(Class<T>) in QueryFactory is applied to Class<B>
unchecked conversion found: Query required: Query<B>
Run Code Online (Sandbox Code Playgroud)
看起来类型擦除再次打击我,但我不明白这些警告.还有什么建议可以让我回到正轨吗?谢谢!
编辑3
如果我将客户端代码更改为,我可以在没有警告的情况下进行编译
Query<BImpl> bQuery = QueryFactory.queryForType(BImpl.class);
Run Code Online (Sandbox Code Playgroud)
但我真的想隐藏API用户的实现类.我试图使B成为抽象类而不是接口,以防问题与此有关,但它没有帮助.
这里,您的接口A声明T了扩展原始类型的类型参数A.你应该试试
// v--- Add this
interface A<T extends A<T>> extends Query<T> { }
Run Code Online (Sandbox Code Playgroud)
这确保了T扩展泛化A的T.这样,T将在其Query界面中指定的界限内.
这将适用于您的第二个版本的AImpl实现A<AImpl>.
编辑
不得不说
interface B<T extends B<T>> extends A<B<T>> { }
Run Code Online (Sandbox Code Playgroud)
看起来过于复杂.对于B接口,从扩展它A就像你扩展A的Query:
// v-- Don't mention B here
interface B<T extends B<T>> extends A<T> { }
Run Code Online (Sandbox Code Playgroud)
然后你的BImpl班级看起来类似于你的AImpl班级:
class BImpl implements B<BImpl> {
public BImpl execute() { ... }
public Query<BImpl> appendClause() { ... }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
331 次 |
| 最近记录: |