Search code examples
javagenericscollectionscomparable

Implement remove(Object o) in generic collection


I am writing a generic collection based on a binary tree model.

class MyTree <T extends Comparable<T>> extends AbstractCollection<T>{...}

The underlying Node<T> class (among others) contains the following methods:

public Node<T> getLeft()  // left Node
public Node<T> getRight() // right Node
public T getValue()       // value stored in the Node

I want to override the method boolean contains(Object o) of the interface AbstractCollection<T> to have the possibility to check for Object's of a type other than T.

For the tree traversal in O(log n) the generic type T must implement Comparable<T>, so it has the method compareTo(T t).

My code:

@Override
public boolean contains(Object o){
    T t = (T) o; // produces warning (see below)
    BSNode<T> currentNode = this.root;
    while(currentNode != null){
        if(currentNode.getValue().equals(o)) {return true;}
        if(currentNode.getValue().compareTo(t) < 0)  {currentNode = currentNode.getRight();}
        if(currentNode.getValue().compareTo(t) > 0)  {currentNode = currentNode.getLeft();}
    }
    return false;
}

The problem is that I can not just cast Object o to T t for using compareTo(T t). Technically the Object's are castable to T, but as T is a generic type, I get this warning:

warning: [unchecked] unchecked cast
          T t = (T) o;
                    ^
required: T
found:    Object
where T is a type-variable:
  T extends Comparable<T> declared in class MyTree

Can someone either

  1. confirm that I can safely ignore the warning using @SuppressWarnings("unchecked"),
  2. suggest how I can safely cast Object to T,
  3. explain why neither of the points above can be satisfied so I can stop thinking about how to make this work?

Thanks a lot!


Solution

  • If you would like to have unrestricted searches, you need to do a cast. You can add instanceof to guard the cast from exceptions, but that is not ideal either.

    Consider changing the bounds of T as follows:

    class MyTree <T extends Comparable<? super T>> extends AbstractCollection<T>{...}
    

    Since you do an override, suppressing the warning is pretty much required. The cast should look as follows:

    @SuppressWarnings("unchecked")
    Comparable<? super T> t = (Comparable<? super T>) o;
    

    See the source of getEntry method of java.util.TreeMap for an example of how it is done in Java source (they do it for the same reason - the need to override a method with a signature taking Object).