在进行继承时避免从超类转换为子类

时间:2013-09-24 23:12:59

标签: java inheritance

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

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
}

我后来需要一个只接受可比较的Ts的子类, 定义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对象 但他们的字段仍然是BTNode并导致像isBST()这样的地方出现问题。 getLeft()返回一个BTNode但isBST仅为CBTNodes定义。当我尝试转换为CBTNode时,Java不喜欢它。

扩展/委托/其他CBTNode的首选方式是什么? 它不是一个大类 - 我可以切断两个节点之间的链接,只是将CBTNode定义为BTNode的副本,但是使用CBTNode字段,但这看起来非常难看。 我想到了委托新功能,但仍然存在从BTNode转换为CBTNode的问题,而Java对象也是如此。我希望我能够忽略一种明显,优雅的方法,只是等着咬我的鼻子。

1 个答案:

答案 0 :(得分:4)

正如吉姆所说,你可以覆盖getters - getLeft(),getRight(),getParent() - 来缩小类型。

这方面并不是特别容易。以上是唯一真正有效的解决方案..我已经有很多代码触及了这个&amp;非常相似的情况。

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> - 你会发现它为代码增加了很多复杂性但却没有实际上有所帮助。 (除非完全指定所有类型参数,否则推理不起作用,转换会变得很痛苦,而且它似乎并不真正起作用。)

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