Java 不强制转换的继承

Java Inheritance without casting

public class BinaryVertex {
  public BinaryVertex parent,left,right;
}

public class BSTVertex extends BinaryVertex {
  public void foo() {
    left = new BSTVertex();
    if(Math.floor(Math.random()*2) == 0) left.foo();
  }
}

我正在为学校制作一棵树/图 api,从 oop 的角度来处理它。但是我试图找出一种方法让继承的 class 将它的一些基础 class 变量视为它自己的类型(即 parent,left,right 在调用时应该被视为 BSTVertex来自 BSTVertex,但当从 BinaryVertex) 调用时被视为 BinaryVertex,无需转换。

我正在考虑泛型,但我不确定在这种情况下如何实现它。

更新

很好,不知道您可以在泛型中使用扩展。但是我收到 BSTVertex<T> cannot be converted to T 错误:

public class Test {
  public static void main(String[] args) {
  new AVLVertex();
  BSTVertex<BSTVertex> v = new BSTVertex<BSTVertex>();
  v.foo();
}
class BinaryVertex<T extends BinaryVertex> {
  public T parent, left, right;
}
class BSTVertex<T extends BSTVertex> extends BinaryVertex<T> {
  public T foo() {
    return this; //error here
  }
}
class AVLVertex extends BSTVertex<AVLVertex> {
  // this might probably end up being abstract too
}

foo 需要 return 一个与调用者类型相同的顶点,即如果 AVLVertex 调用 foo 它期望得到 AVLVertex 而不是 BSTVertex

是的,您可以像这样使用泛型:

public class BinaryVertex<T extends BinaryVertex<T>> {
    public T parent, left, right;
}

public class BSTVertex extends BinaryVertex<BSTVertex> {
  public void foo() {
    left = new BSTVertex();
    if(Math.floor(Math.random()*2) == 0) left.foo();
  }
}

Comparable 接口实现的方式相同,因此 subclasses 接收与 compareTo 方法相同的类型。例如,Integer implements Comparable<Integer>,因此其 compareTo 方法接收 Integer 参数。

另请注意,最好像这样创建您自己的随机数生成器:

public class BSTVertex extends BinaryVertex<BSTVertex> {
  private static final Random r = new Random();
  public void foo() {
    left = new BSTVertex();
    if(r.nextBoolean()) left.foo();
  }
}

更新

在您更新的代码中(将来请提出新问题)您不能安全地转换,因为您以后可能会写:

class RBVertex extends BSTVertex<RBVertex>{}
class AVLVertex extends BSTVertex<RBVertex>{}

从编译器的角度来看这是可以的,但是您的 AVLVertex 泛型参数实际上不是 AVLVertex。这就是为什么你在 foo() 方法中有一个编译错误:你的 class 以后可能会以一种使你的 T 与此不兼容的方式扩展。

您可以通过执行未经检查的转换来解决此问题:

@SuppressWarnings("unchecked")
public T foo() {
    return (T) this;
}

这样如果你错误地创建class AVLVertex extends BSTVertex<RBVertex>{},它仍然会编译,但是在调用AVLVertex.foo()时你可能有一个运行时ClassCastException