【问题标题】:How to implement an abstract class of generic type?如何实现泛型类型的抽象类?
【发布时间】:2018-10-29 09:01:09
【问题描述】:

我正在开发一个关于二叉搜索树的 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 泛型变量?

【问题讨论】:

  • BsNode&lt;T extends BsNode&lt;T&gt;&gt;。否则它是一个原始类型。
  • 你不能禁止滥用,只能让它变得更难。
  • @AndyTurner 但这仍然不能阻止public class RedBlackNode extends BsNode&lt;AvlNode&gt; 的情况,并且在引用this 时还需要(T) 向下转换。
  • 不,它不需要投射任何东西。
  • BsNode 有一个递归的T containsNode(int searchVal) 方法。假设找到该值,我想返回this(作为包含给定值的节点),但this 指的是BsNode&lt;T&gt; 而不仅仅是T

标签: java oop generics inheritance tree


【解决方案1】:

正如 cmets 中所述,这不可能在编译时强制执行。有一个技巧可以强制它在运行时失败。

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

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

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

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

【讨论】:

  • 据我所知,我无法将this 发送到super(T),因为在super 初始化之前this 尚未定义...
  • @A.Kali 谢谢你是对的!我通过传递假定的类型参数类来修复它。
猜你喜欢
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 2012-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 2013-03-06
相关资源
最近更新 更多