Java - 有界泛型方法

时间:2017-05-29 17:35:07

标签: java generics bounded-wildcard

给定具有以下部分实现的通用类型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在这种情况下是生产者。

实际可行的唯一解决方案是将leftright放到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泛型及其限制的丑陋真相,或者我是否做错了。

2 个答案:

答案 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);
    }
}