Why is T bounded by Object in the Collections.max() signature?

JavaGenerics

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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 for max() 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMaxim KirilovView Question on Stackoverflow
Solution 1 - JavaBenjamin GruenbaumView Answer on Stackoverflow