Warum ist T in der Collections.max () - Signatur durch Object begrenzt?

73

java.util.CollectionsIch habe gerade die Implementierung der Java 7- Klasse durchlaufen und etwas gesehen, das ich nicht verstehe. maxWarum ist in der Funktionssignatur Tbegrenzt durch 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 scheint gut zu funktionieren, wenn das gebundene Objekt weggelassen wird.

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;
}

Gibt es tatsächlich Situationen, in denen die Grenze einen Unterschied macht? Wenn ja, geben Sie bitte ein konkretes Beispiel an.

Maxim Kirilov
quelle
4
Duplikat von <T erweitert Objekt & E> vs <T erweitert E>, obwohl dieser Beitrag sowohl eine bessere Frage als auch eine bessere Antwort enthält.
Paul Bellora

Antworten:

87

Die beiden haben die gleichen Grenzen, aber es gibt einen subtilen Unterschied.

 <T extends Object & Comparable<? super T>> 

Dies führt Tzu einer ObjectUnterlöschung.

 <T extends Comparable<? super T>>

Dies führt Tzu einer ComparableLöschung.


In diesem Fall geschieht dies, weil es .maxälter als Java 5 ist. Wir können in diesem Link sehen, dass Joachim freundlicherweise vorausgesetzt hat, dass die Signatur von .maxin Java 1.4.2 lautet:

public static Object max(Collection coll)

Hätten wir <T extends Comparable<? super T>>als Bindung verwendet, wäre unsere Unterschrift

public static Comparable max(Collection coll)

Welches würde die APIs brechen. Ich habe es geschafft, diese Seite zu finden , auf der die Konvertierung alter APIs in generische erläutert wird, und die .maxein konkretes Beispiel enthält.

Hier erklären sie, warum maxdies so definiert ist:

Sie müssen auch sicherstellen, dass die überarbeitete API die Binärkompatibilität mit alten Clients beibehält. Dies bedeutet, dass das Löschen der API mit der ursprünglichen, nicht generierten API identisch sein muss. In den meisten Fällen fällt dies natürlich aus, aber es gibt einige subtile Fälle. Wir werden einen der subtilsten Fälle untersuchen, die uns begegnet sind, die Methode Collections.max(). Wie wir im Abschnitt Mehr Spaß mit Wildcards gesehen haben, ist eine plausible Signatur für max():

public static <T extends Comparable<? super T>> T max(Collection<T> coll)Dies ist in Ordnung, außer dass das Löschen dieser Signatur wie folgt lautet: Dies public static Comparable max(Collection coll)unterscheidet sich von der ursprünglichen Signatur von max ():public static Object max(Collection coll)

Man hätte diese Signatur sicherlich für max () angeben können, aber es wurde nicht getan, und alle alten Binärklassendateien, die Collections.max () aufrufen, hängen von einer Signatur ab, die Object zurückgibt.

Benjamin Gruenbaum
quelle
Gibt es einen Grund, warum dies wünschenswert wäre?
Templatetypedef
Vielleicht, weil Collection.maxvor Java 5 und als solche vor Generics. Und da der Rückgabewert ist T, würde dies die Signatur der Methode nach dem Löschen ändern.
Joachim Sauer
@templatetypedef Ja, hauptsächlich in altem Code. Da Java nicht immer über Generika verfügt, deren Signatur nach dem Löschen nach dem Löschen dieselbe bleibt wie die Signatur vor dem Generieren, ist dies wünschenswert. Ich erinnere mich, dass ich in docs.oracle.com darüber gelesen habe - ich brauche etwas mehr, um es zu finden.
Benjamin Gruenbaum
Ich habe nie über die Signatur von Generika nach dem Löschen von Typen nachgedacht.
Shashank