Problem with <T extends Comparable <? super T >>
I have three classes: 1.class Algorithm having max() to find the maximum value in 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 Fruit extension:
public class Apple extends Fruit { public Apple(int size) { super("Apple", size); } } Now the question is:
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 Java post - Syntax Question: What is it , I should write it like this: public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll) public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll) . But now it works fine. Why? The Apple class does not implement Comparable<Apple> and there is no super .
[UPDATE]
Java Generics and Collections Book says:
Without the
superwildcard character, finding the maximum of aList<Apple>would be illegal, although finding the maximum ofList<Fruit>is allowed.
Suppose we change the max method to this:
<T extends Comparable<T>> T max(Collection<? extends T> coll) You cannot get max for List<Apple> because Apple does not implement Comparable<Apple> , it implements Comparable<Fruit> . But you and I know very well that Apple can compare itself with other Fruit , because it has inherited this functionality.
We fix the problem by changing the max declaration to this:
<T extends Comparable<? super T>> T max(Collection<? extends T> coll) This means that we accept any class T such that:
T implements Comparable<T>, or ...T implements Comparable<X>for someXsuch thatXis a superclass ofT
To find max , we need to 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
This example shows a second scenario where T corresponds to Apple and X corresponds to Fruit .
Sorry to have returned this, but I think it is important. Does your code stop working properly when it is changed from Collections.max () to Algorithm.max ()? I did a simple test in jdk8 and I donβt understand why it works fine, while according to Java Generics and Collections it should not.
I have an abstract Fruit class (Comparable implementation):
public abstract 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; } } Then I have Apple extending the Fruit class:
public class Apple extends Fruit { public Apple(String name, int size) { super(name, size); } } And finally:
public class GenericsTest { @Test public void test1() { final Apple a1 = new Apple("apple1", 50); final Apple a2 = new Apple("apple2", 70); final Apple a3 = new Apple("apple3", 34); final List<Apple> apples = Lists.newArrayList(a1, a2, a3); System.out.println(GenericsTest.max(apples).getSize()); } private 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; } } Does the code work yet? super T is in the signature of the maximum method, and List is of type Apple. According to the quote you quoted, it should not work. It seems I'm puzzled here ...