Search code examples
javagenericstreecomparablegeneric-programming

What is the difference between these class declarations with Comparable?


Here is one declaration

public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
   ....
}

Here is the other declaration

public class BinarySearchTree<AnyType extends Comparable<AnyType>>{
    .....
}

I know the first declaration is preferred(seen it in alot of java examples and textbooks) but why is that? All my code ran fine when I tried using the second declaration as well.

I know that super used in this context, ? super AnyType, means AnyType or any of its super classes. Super

To me both are saying that this class, BinarySearchTree, supports any object type that is comparable. Can anyone describe or give an example of where this subtle difference actually makes a difference?

With dog example

class Animal implements Comparable<Animal>
class Dog extends Animal
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
  ...}
Would allow for  
BinarySearchTree<Dog> but 
 public class BinarySearchTree<AnyType extends Comparable<AnyType>>{
    .....
} wouldn't

Solution

  • If you have

    class Animal implements Comparable<Animal>
    class Dog extends Animal
    

    then BinarySearchTree<Dog> would be legal with the first signature but not with the second. It's not legal with the second signature because Dog does not implement Comparable<Dog> (and there is no way to make it implement Comparable<Dog>, since it already implements Comparable<Animal>, and a type cannot implement an interface with two different type arguments).

    If you think about it, BinarySearchTree<Dog> is perfectly fine because Dogs are comparable to themselves (in fact they are comparable to all Animals, which includes all Dogs). All we need is to guarantee someDog.compareTo(someOtherDog) works. For this to work, we don't need that compareTo take exactly Dog -- any supertype of Dog will also work. That's what the ? super represents. It relaxes the constraint to a more general one that still provides all the type guarantees we need. In generics, we should always use the least restrictive bounds that give us the type safety we need.

    Another way to think about it is through the PECS rule (Producer extends, Consumer super). A Comparable<T> can only be a "consumer" of T, because its only method takes a parameter of type T, and it does not return T. Therefore, Comparable should always be used with a ? super ... wildcard.