I use comparable interface all the time to provided natural ordering for my class through collection.sort.
Basically if I have a person class, I will get it to implement Comparable interface and will provide the implementation of compareTo. However in the definition of Collections.sort in javadocs, I see this signature
public static <T extends Comparable<? super T>> void sort(List<T> list)
I don't understand this generics definition at all? Shouldn't it just say
<T implements Comparable<T>>
Can someone help me with this?
Actually, it means that T can implement Comparable<? super T>
, not just Comparable<T>
.
For example, it means that a Student
class can implement Comparable<Person>
, where Student
is a subclass of Person
:
public class Person {}
public class Student extends Person implements Comparable<Person> {
@Override public int compareTo(Person that) {
// ...
}
}
In this case, a List can be sorted by Collections.sort()
but only based on Person
's properties, because you pass the Student
instance into compareTo()
as a Person
(unless you downcast it, of course).
In practice however, you'll never see a Student
class implement Comparable<Person>
. That's because Person
will probably have implemented Comparable<Person>
, and Student
inherits it implementation. The end result is the same however: you can pass a List<Student>
to Collections.sort()
and have it sorted on Person
's properties.
The difference between Comparable<T>
and Comparable<? super T>
is more obvious in the overloaded version of Collections.sort() that takes a Comparator<? super T>
:
class ByAgeAscending implements Comparator<Person> {
@Override public int compare(Person a, Person b) {
return a.getAge() < b.getAge();
}
}
List<Student> students = getSomeStudents();
Collections.sort(students, new ByAgeAscending());
You always use extends with generics wildcards, even if the type parameter implements an interface.
If you look at a class that implements Comparable, you'll see that it actually (should) implement Comparable<T>
, where T is the class itself.
It makes sense if you think about the type paramter passed to the Comparable interface and how it's used in the compareTo() method.
As PM 77-1 has eloquently pointed out, the super keyword allows for either the class, T, or one of its parents to implement Comparable.