user986139
user986139

Reputation:

Returning Subclass of generic superclass in a superclass method

I am new to Java coming from a PHP background so sorry if this maybe obvious. I'm trying to implement a binary tree class and I've created an ADT like so:

public abstract class BTree<T> {
    private T value;
    private BTree<T> leftChild;
    private BTree<T> rightChild;
    private BTree<T> parent;
    public BTree<T> getLeftChild() { return this.leftChild; }
    ....
} 

Then I have another class that extends this like so:

public class BIntTree extends BTree<Integer> {
}

However I want to be able to within BIntTree to have a method where I can call this.getLeftChild(); and get an instance of BIntTree back rather than a instance of BTree<Integer>

Is this possible with some way of defining the generic class / method or do I have to explicitly type cast it after I used this.getLeftChild() or even override the superclass method?

My current solution is to explicitly typecast it in the BIntTree method with BIntTree b=(BIntTree) this.getLeftChild(); which seems untidy to me.

Also I'm not so sure what would happen if I had that type casting defined and getLeftChild() returned null, would an exception be thrown? If so how do I cure this given that null is also a valid value if exist?

Upvotes: 3

Views: 2145

Answers (3)

Mark Peters
Mark Peters

Reputation: 81074

It is possible to have a self-typed class, but you have to wonder why you want it. Why do you need to know that it is a BIntTree rather than a BTree<Integer>? What have you gained with your use of generics?

Anyway, you could do something like this:

public abstract class BTree<V, T extends BTree<V, T>> {
    public T getLeft() {...}
    public T getRight() {...}
    public V getValue() {...}
}

Then your BIntTree would be

public class BIntTree extends BTree<Integer, BIntTree> {
    //...
}

Edit

With regards to your question about casting null, there is really nothing preventing you from testing the behaviour yourself. But to answer your question, it is safe to cast null to any type.

Upvotes: 4

Igor Nikolaev
Igor Nikolaev

Reputation: 4697

You can override required method like this:

public class BIntTree extends BTree<Integer> {
    @Override
    public BIntTree getLeftChild() { return (BIntTree) super.getLeftChild(); } 
}

As of vertion 1.5 Java supports covariant return types - meaning you can return type with it's subclass.

Upvotes: 1

Mansoor Siddiqui
Mansoor Siddiqui

Reputation: 21663

First of all, I would imagine that you'd want to make value, leftChild, rightChild, and parent protected, not private, so that they can be accessed from the subclass.

Once you make that change, you can have BIntTree.getLeftChild() return a BTree<Integer> simply by defining your subclass as follows:

public class BIntTree extends BTree<Integer> {
    public BTree<Integer> getLeftChild() { return this.leftChild; }
    ...
}

I'll just add that you should only really be defining such a class if you have some Integer-specific logic happening here. Otherwise, it would make sense to leave the type of T up to whoever uses your BTree class.

Upvotes: 1

Related Questions