给定具有以下部分实现的通用类型Result<T>
public class Result<T> {
/* fields, ctor, etc... */
public Result<T> mergeWith(Result<? extends T> other) {
/* fiddle with this and other (acting as producer) and return */
}
/* other methods */
}
并在访客中使用它......
接口:
public interface Visitor<T> {
T visitFile(FileContext ctx);
T aggregate(T left, T right);
/* ... */
}
实现:
public class SomeVisitor implements Visitor<Result<? extends Node>> {
// this works fine, as I can return subtypes of 'Node'
@Override
public Result<FileNode> visitFile() { }
/* ... */
@Override
public Result<? extends Node> aggregate(Result<? extends Node> left,
Result<? extends Node> right) {
// This line completely blows up.
Result<? extends Node> tempResult = left.mergeWith(right);
// Expected type: 'Option<? extends capture of ? extends Node>'
// Have type: 'Option< ? extends Node>'
}
SomeVisitor
的调用点:
FileContext fileCtx = someOtherService.acquireFileContext();
SomeVisitor visitor = new SomeVisitor();
Result<FileNode> fileNodeResult = visitor.visitFile(fileCtx);
// process the result
上面的示例因给定的类型不匹配错误消息而失败。
我已经尝试更改.mergeWith的签名以接受更窄的Result<T>
而不是Result<? extends T>
。在此示例中,这会导致预期的Result<capture of ? extends Node>
类型。并在其他地方打破它,其中<? extends T>
是正确的泛型类型,因为other
在这种情况下是生产者。
实际可行的唯一解决方案是将left
和right
放到Result<Node>
,合并它们然后返回:
@SuppressWarnings("unchecked")
Result<Node> tempLeft = (Result<Node>) left;
@SuppressWarnings("unchecked")
Result<Node> tempRight = (Result<Node>) right;
Result<Node> tempResult = tempLeft.mergeWith(tempRight);
不仅是丑陋而且引入了临时变量,当我内联演员时,它也不会变得更漂亮。
我想知道这是否只是关于Java泛型及其限制的丑陋真相,或者我是否做错了。
答案 0 :(得分:0)
根据Result的合并声明,您可以合并Result&lt; S&gt;结果&lt; T&gt;当且仅当T是S的子类型时。
在你的聚合方法中,left的type参数是Node的一些未知子类,right的type参数也是Node的一些未知子类。不能保证right的type参数是left的子类。
如果您尝试这样做怎么办:
public <S extends Node, T extends S> Result<? extends Node> aggregate(Result<S> left, Result<T> right) {
Result<? extends Node> temp = left.mergeWith(right);
/** do stuff*/
return temp;
}
这里,我们声明两种类型S和T,并要求S是Node的子类型,T是S的子类型。
答案 1 :(得分:0)
问题来自?
捕获,它们彼此独立。不要在类定义中使用?
捕获。使用泛型类型标识符:
public class SomeVisitor<T extends Node> implements Visitor<Result<T>> {
public Result<FileNode> visitFile() { }
/* ... */
protected Result<T> aggregate(Result<T> left, Result<T> right) {
Result<T> tempResult = left.mergeWith(right);
}
}