如何实现泛型类型的抽象类?

时间:2018-05-18 21:24:57

标签: java oop generics inheritance tree

我担心有关二叉搜索树的Java项目。我们被要求实现和AVL树,但也建议保持良好的抽象,以实现其他类型的树(如红黑树)。我决定使用abstract BsNode类(Bs =二分搜索)和abstract BsTree类,并通过以下方式使用AvlTreeAvlNode实现它们:

public abstract class BsNode<T extends BsNode> {
    T parent
    T left
    T right
    ...
}

public abstract class BsTree<T extends BsNode> {
    T root
    ...
}

public class AvlNode extends BsNode<AvlNode> {
    int balance;
    ...
}

public class AvlTree<AvlNode> {
    private void rotate(int direction);
    ...
}

这会导致两个问题:首先,BsNode需要接收它的继承者类型并不意味着我。其次,这开启了发生这种事情的可能性:

public class RedBlackNode extends BsNode<AvlNode> {
    ...
}

RedBlackNode myRoot = new RedBlackNode<AvlNode>();

这些不应该被允许。如何在BsNode中强制使用继承类(意味着保持parent和子指针指向实现类的类型)而不是传递T泛型变量?

1 个答案:

答案 0 :(得分:1)

正如评论中所提到的,这不可能在编译时强制执行。有一种技巧可以在运行时强制它失败。

您要做的是请求实现类将自己的类型参数类传递给抽象构造函数,并使用类型参数类键入参数。

父类构造函数验证这个类确实是与类型参数对应的类相同的类。

abstract class BsNode<T extends BsNode<T>> {

   protected BsNode(final Class<T> clazz) {
       if (!this.getClass().equals(clazz)) 
          throw new IllegalArgumentException("invalid mixture of node types");
   } 
}

class AvlNode extends BsNode<AvlNode> {

   public AvlNode() {
        super(AvlNode.class); // works!!!
   }

}

class RBNode extends BsNode<AvlNode> {

   public RBNode() {
       // two possible super calls:
       super(AvlNode.class); // fails at run-time.
       // or
       super(RBNode.class); // fail at compilation-time.
   }
}

如果您的软件包含测试的正式构建过程,那么将约束检查留出生产代码(节省计算时间)可能更有意义,而是将其作为单元测试的一部分