在执行继承时避免从超类转换到子类



我在处理树问题时遇到了这个问题:

class BTNode<T> {
    private final T value;
    private BTNode<T> parent;
    private BTNode<T> left;
    private BTNode<T> right;
    public BTNode(T aValue) { 
       value = aValue; 
       left = right = parent = null;
    }
  the obvious protected getters & setters
}

我后来需要一个只接受可比较的 T 的子类,定义 compareTo,并添加使用该属性的新方法。除了让 Java 开心。

class CBTNode<T extends Comparable<T>> extends BTNode<T> 
                        implements Comparable<CBTNode<T>> {
    CBTNode(T aValue) { super(aValue); }
    T isBST() .... calls getLeft().isBST()  // for example
}

继承通常很简单,但父类的字段是所有键入的BTNode似乎使这比我希望的要困难得多是由于运行时的类转换错误造成的。 我可以创建 CBTNodes 的对象但他们的字段仍然是BTNodes,并在isBST((等地方引起问题。getLeft(( 返回一个 BTNode,但 isBST 只为 CBTNodes 定义。 当我尝试投射到CBTNode时,Java不喜欢它。

扩展/委托/其他CBTNode的首选方式是什么?它不是一个大类 - 我可以切断两个节点之间的链接,只需将CBTNode定义为BTNode的副本,但是使用CBTNode字段,但这似乎很丑陋。我想过委派新功能,但仍然会遇到从BTNode转换为CBTNode的问题,这是Java反对的。 我希望我忽略了一种明显、优雅的方法,它正等着咬我的鼻子。

正如 Jim 所说,你可以覆盖 getters - getLeft((, getRight((, getParent(( -- 来缩小类型范围。

这个领域不是特别容易,以上是唯一真正整洁的解决方案。我有很多代码涉及这个和非常相似的情况。

public class CBTNode<T extends Comparable<T>> 
        extends BTNode<T>
        implements Comparable<CBTNode<T>> 
        {
    @Override
    protected CBTNode<T> getParent() {return (CBTNode<T>) parent;}
    @Override
    protected CBTNode<T> getLeft() {return (CBTNode<T>) left;}
    @Override
    protected CBTNode<T> getRight() {return (CBTNode<T>) right;}

另一种可能的替代方案 - 将类泛化反对自身 - 实际上不起作用。

如果您尝试使用泛型来处理这个问题 - 例如将节点类型本身作为泛型参数,例如class BTNode<T, NodeT extends BTNode> - 您会发现它增加了代码的很多复杂性,但实际上并没有帮助。(除非完全指定所有类型参数,否则推理不起作用,强制转换变得痛苦,而且它似乎真的不起作用。

曾经的问题是不同边界的泛型之间的强制转换是不合法的 - 泛型规则更严格,因为编译器无法验证它们是否合法,或者由于擦除而在运行时测试它们。这里丑陋的解决方法是使用两个强制转换 - 首先强制转换为原始类型,然后转换为所需的参数化类型。

最新更新