Search code examples
javagenericscollections

Problem with <T extends Comparable<? super T>>


I have a three class: 1.class Algorithm having max() finding maximum value in a Collection:

public class Algorithm {

    public static <T extends Comparable<T>> T max(Collection<? extends T> coll) {
        T max = coll.iterator().next();

        for (T elm : coll) {
            if (max.compareTo(elm) < 0)
                max = elm;
        }

        return max;
    }
}

2.Class Fruit:

public class Fruit implements Comparable<Fruit> {
    private String name;
    private int size;

    public Fruit(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public int compareTo(Fruit that) {
        if (size < that.size)
            return -1;
        else if (size == that.size)
            return 0;
        else
            return 1;
    }
}

3.class Apple extending Fruit:

public class Apple extends Fruit {
    public Apple(int size) {
        super("Apple", size);
    }
}

Now the question is this:

public class Main
{
    public static void main(String[] args) {        
        Apple a1 = new Apple(10);
        Apple a2 = new Apple(34);

        List<Apple> apples = Arrays.<Apple>asList(a1, a2);

        System.out.println(Collections.max(apples).size);
    }
}

According to this post Java - Syntax Question: What is I should wrote it this way: public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll). But it is working fine now.Why? Class Apple does not implement Comparable<Apple> and there is no super.

[UPDATE]
Java Generics and Collections Book says:

Without the super wildcard, finding the maximum of a List<Apple> would be illegal, even though finding the maximum of a List<Fruit> is permitted.


Solution

  • Suppose we changed the max method to this:

    <T extends Comparable<T>> T max(Collection<? extends T> coll)
    

    You would not be able to get the max of a List<Apple> because Apple does not implement Comparable<Apple>, it implements Comparable<Fruit>. But you and I know perfectly well that an Apple knows how to compare itself to another Fruit because it inherited that functionality.

    We fix the problem by changing the declaration of max to this:

    <T extends Comparable<? super T>> T max(Collection<? extends T> coll)
    

    This means that we accept any class T such that:

    1. T implements Comparable<T>, or...
    2. T implements Comparable<X> for some X such that X is a super class of T

    In order to find the max, we must be sure that any instance of T can safely accept another instance of T as an argument to its compare method.

    In the first scenario, it is obvious that any instance of T can safely accept another instance of T as an argument to its compare(T) method.

    In the second scenario, any instance of T can safely accept another instance of T as an argument to its compare(X) method because all instances of T are also instances of X.

    Your example illustrates the second scenario, where T corresponds to Apple and X corresponds to Fruit.