简体   繁体   English

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

[英]How to implement an abstract class of generic type?

I'm woriking on a Java project regarding binary search trees. 我担心有关二叉搜索树的Java项目。 We were asked to implenet and AVL tree, but also advised to keep good abstraction in order to implement other types of trees (such as red-black tree). 我们被要求实现和AVL树,但也建议保持良好的抽象,以实现其他类型的树(如红黑树)。 I decided to use an abstract BsNode class (Bs = binary search) and an abstract BsTree class, and implement them with AvlTree and AvlNode in the following way: 我决定使用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);
    ...
}

This causes two problems: First, it doesn't make sence to me that BsNode needs to receive it's inheritor type. 这会导致两个问题:首先, BsNode不需要接收它的继承者类型。 Second, this opens the possibilty for such a thing to happen: 其次,这为这样的事情开启了可能性:

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

or 要么

RedBlackNode myRoot = new RedBlackNode<AvlNode>();

and these should not be allowed. 这些不应该被允许。 How can I enforce the usage of the inheriting class in BsNode (meaning to keep the parent and children pointers to the type that is implementing the class) instead of passing the T generic variable? 如何在BsNode强制使用继承类(意味着保持parent和子类指向实现类的类型)而不是传递T泛型变量?

As mentioned in comments this is not possible to enforce at compilation time. 正如评论中所提到的,这不可能在编译时强制执行。 There is a trick to force it to fail at run-time. 有一种技巧可以在运行时强制它失败。

What you do is to request implementing classes to pass their own type-parameter class to the the abstract constructor with an argument typed with the type-parameter class. 您要做的是请求实现类将自己的类型参数类传递给抽象构造函数,并使用type-parameter类键入参数。

The parent class constructor verifies that indeed this's class is the same class as the class that corresponds to the type-parameter's. 父类构造函数验证这个类确实是与类型参数对应的类相同的类。

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.
   }
}

If you have a formal build process as part of your software that contains testing, it might make more sense to leave the constrain check out of the production code (saving the computation time) and instead make it part of your unit-tests. 如果您有一个正式的构建过程作为包含测试的软件的一部分,那么将约束检查留出生产代码(节省计算时间)并将其作为单元测试的一部分可能更有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM