Reputation: 694
Why does Collections.sort(List<T>)
have the signature :
public static <T extends Comparable<? super T>> void sort(List<T> list)
and not :
public static <T extends Comparable<T>> void sort(List<? extends T> list)
Upvotes: 25
Views: 1533
Reputation: 132460
// 0
public static <T extends Comparable<? super T>> void sort0(List<T> list)
// 1
public static <T extends Comparable<T>> void sort1(List<? extends T> list)
These signatures differ because they impose different requirements on the relationship between type T
and the type argument to Comparable
in the definition of T
.
Suppose for example that you have this class:
class A implements Comparable<Object> { ... }
Then if you have
List<A> list = ... ;
sort0(list); // works
sort1(list); // fails
The reason sort1
fails is that there is no type T
that is both comparable to itself and that is, or is a supertype of, the list's type.
It turns out that class A
is malformed, because objects that are Comparable
need to meet certain requirements. In particular reversing the comparison should reverse the sign of the result. We can compare an instance of A
to an Object
but not vice-versa, so this requirement is violated. But note that this is a requirement of the semantics of Comparable
and is not imposed by the type system. Considering only the type system, the two sort
declarations really are different.
Upvotes: 9
Reputation: 100269
Your proposed signature would probably work in Java-8. However in previous Java versions type inference was not so smart. Consider that you have List<java.sql.Date>
. Note that java.sql.Date
extends java.util.Date
which implements Comparable<java.util.Date>
. When you compile
List<java.sql.Date> list = new ArrayList<>();
Collections.sort(list);
It perfectly works in Java-7. Here T
is inferred to be java.sql.Date
which is actually Comparable<java.util.Date>
which is Comparable<? super java.sql.Date>
. However let's try your signature:
public static <T extends Comparable<T>> void sort(List<? extends T> list) {}
List<java.sql.Date> list = new ArrayList<>();
sort(list);
Here T
should be inferred as java.util.Date
. However Java 7 specification does not allow such inference. Hence this code can be compiled with Java-8, but fails when compiled under Java-7:
Main.java:14: error: method sort in class Main cannot be applied to given types;
sort(list);
^
required: List<? extends T>
found: List<Date>
reason: inferred type does not conform to declared bound(s)
inferred: Date
bound(s): Comparable<Date>
where T is a type-variable:
T extends Comparable<T> declared in method <T>sort(List<? extends T>)
1 error
Type inference was greatly improved in Java-8. Separate JLS chapter 18 is dedicated to it now, while in Java-7 the rules were much simpler.
Upvotes: 19
Reputation: 201467
They differ because ? super T
is less restrictive than T
. It is a Lower Bounded Wildcard (the linked Java Tutorial says, in part)
The term
List<Integer>
is more restrictive thanList<? super Integer>
because the former matches a list of typeInteger
only, whereas the latter matches a list of any type that is a supertype ofInteger
.
Replace Integer
with T
and it means a T
or a java.lang.Object
.
Upvotes: 4