Why is T bounded by Object in the Collections.max() signature?
Just went through the implementation of Java 7's java.util.Collections
class, and saw something that I don't understand. In the max
function signature, why is T
bounded by Object
?
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
max
seems to work fine if the Object bound is omitted.
public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
Are there actually any situations where the bound makes a difference? If yes, please provide a concrete example.
The two have the same bounds but there is a subtle difference.
<T extends Object & Comparable<? super T>>
This will cause T
to become an Object
under erasure.
<T extends Comparable<? super T>>
This will cause T
to become Comparable
under erasure.
In this case it is done because .max
predates Java 5. We can see in this link Joachim kindly provided that the signature of .max
in Java 1.4.2 is:
public static Object max(Collection coll)
Had we used <T extends Comparable<? super T>>
as a bound, our signature would be
public static Comparable max(Collection coll)
Which would break the APIs. I've managed to find this page that discusses converting old APIs to generic ones and it gives .max
as a specific example.
Here they explain why max
is defined this way:
You also need to ensure that the revised API retains binary compatibility with old clients. This implies that the erasure of the API must be the same as the original, ungenerified API. In most cases, this falls out naturally, but there are some subtle cases. We'll examine one of the subtlest cases we've encountered, the method
Collections.max()
. As we saw in section More Fun with Wildcards, a plausible signature formax()
is:
public static <T extends Comparable<? super T>> T max(Collection<T> coll)
This is fine, except that the erasure of this signature is:public static Comparable max(Collection coll)
which is different than the original signature of max():public static Object max(Collection coll)
One could certainly have specified this signature for max(), but it was not done, and all the old binary class files that call Collections.max() depend on a signature that returns Object.