Reputation: 317
I was recently writing a simple generic selection sort method for the fun of it, when I got a little confused about something. Here's my code:
public static <T extends Comparable<T>> void sort(List<T> list) {
for (int i = 0; i < list.size(); i++) {
int minIndex = i; // Assume that the first element is the minimum for now.
// Find smallest element in unsorted sub-list.
for (int k = i + 1; k < list.size(); k++) {
if (list.get(k).compareTo(list.get(minIndex)) < 0) {
minIndex = k;
}
}
// Swap smallest element with the first element in unsorted sub-list.
T temp = list.get(i);
list.set(i, list.get(minIndex));
list.set(minIndex, temp);
}
}
The function itself works fine, but I got a little confused about the generics. I use:
<T extends Comparable<T>>
to ensure that the given List has a comparable type. But what if I were to use a raw Comparable instead? That is:
<T extends Comparable>
What exactly would be the repercussions?
Thanks!
Upvotes: 4
Views: 1594
Reputation: 471
Another consequence could be with inheriting a super class, which would implement the nongeneric Comparable(obj).
public abstract Ship implements Comparable {
public int compareTo(obj) {
return ..
}
}
then a subclass would have to implement its own Comparable as well. Without it like this:
public class Boat extends Ship {}
The compiler will complain on Boat that:
Boat is not abstract and does not override abstract method compareTo(java.lang.Object) in java.lang.Comparable
While with using generic version with specific type, when compareTo(T obj) would exist in abstract class T, the inheriting classes wouldn't have to implement its own compareTo unless they want a custom implementation.
Upvotes: 0
Reputation: 43391
Basically, you lose some type safety.
When you have your T temp = list.get(i)
, what can you do with temp.compareTo
?
T extends Comparable<T>
, temp
is Comparable<T>
, meaning you can only pass another T
into compareTo
T extends Comparable
, temp
is Comparable
, meaning you can pass anything into compareTo
The first of those is almost definitely what you want, because comparable types can only handle objects of the same type. For instance, String.compareTo
can only handle String inputs -- if you pass in an Integer, you'll get a ClassCastException.
Given that the only safe input to temp.compareTo
is a reference of type T
, there is usually no good reason to use the raw type. It's occasionally beneficial for getting around the type system, but in most cases it removes type safety without giving you anything in return.
Upvotes: 10
Reputation: 2095
<T extends Comparable>
would be applicable for a mixed type of comparable objects. For example this would be satisfied by both Integer
instances as well as String
instances whereas <T extends Comparable<T>>
ensures that the types are comparable with each other.
An an example, the following would compile but would throw runtime exceptions because of a class cast exception:
public static void main(String[] args)
{
List<? extends Comparable> l = createList(Integer.valueOf(1), "Man");
Collections.sort(l);
}
protected static <T extends Comparable<?>> List<T> createList(T ... args)
{
return Arrays.asList(args);
}
By restricting to <T extends Comparable<T>
this becomes a runtime check as changing the method to this prevents the previous code from compiling.
Upvotes: 1