我在处理树问题时遇到了这个问题:
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对象也是如此。我希望我能够忽略一种明显,优雅的方法,只是等着咬我的鼻子。
答案 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>
- 你会发现它为代码增加了很多复杂性但却没有实际上有所帮助。 (除非完全指定所有类型参数,否则推理不起作用,转换会变得很痛苦,而且它似乎并不真正起作用。)
问题之一是不同界限的泛型之间的转换是不合法的 - 通用规则更严格,因为编译器无法验证它们是合法的,或者由于擦除而在运行时测试它们。这里丑陋的解决方法是使用两个强制转换 - 首先转换为原始类型,然后转换为所需的参数化类型。