令人困惑的重载行为

Confusing behaviour of overloading

我遇到了一种我无法理解的与此代码片段相关的行为。更准确地说,我期望在运算符类型为 Projection 的情况下调用 getUniqueCost 方法(即,当 n.isProjection() 为真时)调用具有 as 的方法签名 private double getUniqueCost(final Projection p) 而不是签名 private double getUniqueCost(final Node p).

注意 Projection 是 Node 的子类。

这里是上述两种方法的代码:

private double getUniqueCost(final Node n){
    if(n.isScan())
        return getUniqueCost(estimateCardinality(n));
    if(n.isJoin())
        return getUniqueCost((NJoin) n);
    if(n.isUnion())
        return getUniqueCost((Union) n);
    if(n.isMaterialization())
        return getUniqueCost(n.getChildren().iterator().next());        
    if(n.isProjection()){ 
        return getUniqueCost(child.isJoin() ? 
            n.getChildren().iterator().next() : ((Projection) n));
    }
    throw new IllegalArgumentException("Unknown node type: " + n.getOperator());
}

private double getUniqueCost(final Projection p){
    return getUniqueCost(estimateCardinality(p)) + 
            getUniqueCost(p.getChildren().iterator().next());
}

真正调用第二个方法的唯一方法是修改第一个方法如下(省略的代码与之前相同):

private double getUniqueCost(final Node n){
    [...]
    if(n.isProjection()){ 
        final Node child = n.getChildren().iterator().next();
        if(child.isJoin()){
            return getUniqueCost(child);
        }

        final Projection proj = (Projection) n;
        return getUniqueCost(proj);
    }
    throw new IllegalArgumentException("Unknown node type: " + n.getOperator());
}

考虑到转换是在实际调用方法之前执行的(即,按值语义调用,在评估方法本身之前评估参数),我期望它足以调用最具体的方法(接受类型 Projection 的参数)。

自从我查看 Java 的类型系统以来已经有一段时间了,我怀疑整个表达式 child.isJoin() ? n.getChildren().iterator().next() : ((Projection) n) 被键入为 Node,由于左边部分那些类型确实是 Node.

有人可以证实吗?如果没有,你对这里发生的事情有更好的了解吗?

另外,有没有办法让第二版代码的写法更简洁(优雅?)?

您的三元条件表达式的类型 - child.isJoin() ? n.getChildren().iterator().next() : ((Projection) n) - 是 n.getChildren().iterator().next()((Projection) n) 都可以分配给的类型。因此,如果其中一个是Node,另一个是Projection,假设ProjectionNode的子class,表达式的类型是Node.

您的第二个片段可以缩短一点:

    if(child.isJoin()){
        return getUniqueCost(child);
    } else {
        return getUniqueCost((Projection) n);
    }

n 转换为 Projection 足以调用重载的 getUniqueCost(final Projection p) 方法。您不需要中间变量。