Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

generics

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.

like image 915
Maxim Kirilov Avatar asked Oct 21 '13 07:10

Maxim Kirilov


1 Answers

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.

like image 79
Benjamin Gruenbaum Avatar answered Oct 21 '22 11:10

Benjamin Gruenbaum