在超类方法中返回泛型超类的子类

时间:2011-11-09 04:23:02

标签: java generics

我是来自PHP背景的Java新手,很抱歉,如果这可能是显而易见的。我正在尝试实现二叉树类,我已经创建了一个ADT:

public abstract class BTree<T> {
    private T value;
    private BTree<T> leftChild;
    private BTree<T> rightChild;
    private BTree<T> parent;
    public BTree<T> getLeftChild() { return this.leftChild; }
    ....
} 

然后我有另一个类扩展了这个:

public class BIntTree extends BTree<Integer> {
}

但是我希望能够在BIntTree中有一个方法,我可以调用this.getLeftChild();并获取一个BIntTree实例,而不是BTree<Integer>的实例

这是否可以通过某种方式定义泛型类/方法,或者在使用this.getLeftChild()后甚至覆盖超类方法时是否必须显式地输入它?

我目前的解决方案是使用BIntTree b=(BIntTree) this.getLeftChild();在BIntTree方法中明确地对其进行类型转换,这对我来说似乎不整洁。

此外,我不太确定如果我定义了类型转换并且getLeftChild()返回null会发生什么,是否会抛出异常?如果是这样,我如何解决这个问题,因为如果存在,null也是一个有效值?

3 个答案:

答案 0 :(得分:4)

有可能有一个自我类型的类,但你不得不想知道为什么你想要它。为什么你需要知道它是BIntTree而不是BTree<Integer>?你使用泛型有什么收获?

无论如何,你可以这样做:

public abstract class BTree<V, T extends BTree<V, T>> {
    public T getLeft() {...}
    public T getRight() {...}
    public V getValue() {...}
}

然后你的BIntTree将是

public class BIntTree extends BTree<Integer, BIntTree> {
    //...
}

修改

关于您关于投射null的问题,实际上没有什么可以阻止您自己测试行为。但要回答您的问题,将null转换为任何类型都是安全的。

答案 1 :(得分:1)

首先,我想你想让valueleftChildrightChildparent受到保护,而非隐私,这样他们就可以可以从子类访问。

完成更改后,只需按以下方式定义子类,即可BIntTree.getLeftChild()返回BTree<Integer>

public class BIntTree extends BTree<Integer> {
    public BTree<Integer> getLeftChild() { return this.leftChild; }
    ...
}

我只想补充一点,如果你在这里发生了一些Integer特定的逻辑,你应该真正定义这样一个类。否则,将T的类型保留为使用BTree类的任何人都是有意义的。

答案 2 :(得分:1)

您可以覆盖所需的方法,如下所示:

public class BIntTree extends BTree<Integer> {
    @Override
    public BIntTree getLeftChild() { return (BIntTree) super.getLeftChild(); } 
}

从Vertion 1.5开始,Java支持协变返回类型 - 这意味着您可以使用它的子类返回类型。