4

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

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 满意之外,getter 和 setter 不需要做任何新的事情。

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 转换为 Java 对象的 CBTNode 的问题。我希望我忽略了一个明显的、优雅的方法,它正等着咬我的鼻子。

4

1 回答 1

4

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

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

于 2013-09-25T00:10:12.123 回答