简体   繁体   中英

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();
  }
}

I'm making a tree / graph api for school, approaching it from a oop standpoint. But im trying to figure out a way for the inherited class to treat some of its base class variables as its own type (ie parent,left,right should be treated as BSTVertex when called from BSTVertex but treated as BinaryVertex when called from BinaryVertex ) without casting.

I'm thinking of generics but I'm not sure how to implement that in this situation.

UPDATE

Nice, didnt know you could use extend in generics. But I'm getting a BSTVertex<T> cannot be converted to T error with this:

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 needs to return a vertex of the same type as caller, ie if AVLVertex calls foo its expecting to get AVLVertex not BSTVertex

Yes, you can use generics like this:

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();
  }
}

The same way the Comparable interface implemented, so subclasses receive the same type to compareTo method. For example, Integer implements Comparable<Integer> , so its compareTo method receives Integer argument.

Also please note the it would be better to create your own random number generator like this:

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

UPDATE

In your updated code (in future please ask new question instead) you cannot safely cast, because you can potentially write later:

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

This is ok from the compiler's point of view, but your AVLVertex generic argument is actually not an AVLVertex . That's why you have a compilation error in foo() method: your class can be later possibly extended in the way that would make your T incompatible with this.

You can fix this problem by doing an unchecked cast:

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

In this way if you mistakenly create class AVLVertex extends BSTVertex<RBVertex>{} , it will still compile, but upon calling AVLVertex.foo() you may have a runtime ClassCastException .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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