Warum verwenden die Utility-Factory-Methoden häufig einen spezifischen generischen Parameter (wie T
) anstelle eines beschränkten Wildcard-Parameters (wie ? super T
)?
Zum Beispiel die Signatur von Funktionen # forPredicate ist:
%Vor%Warum nicht verwenden:
%Vor%Was würde so etwas wie möglich machen?
%Vor% Liegt das daran, dass Konsumenten von Function
und Predicate
die erforderlichen beschränkten Wildcard-Parameter haben müssen, um dies unnötig zu machen? Beispiel: Die generischen Grenzen für Iterables # find würde erlauben, dass Predicate<Number>
auf einem Iterable<Integer>
verwendet wird:
Gibt es andere Gründe?
Ja, es ist absolut richtig, dass wir erwarten, dass die Verbraucher die richtigen begrenzten Wildcard-Parameter haben, aber ein paar weitere Gründe fallen einem ein:
T
explizit angeben müssen, durch die Beibehaltung der schmaleren Generika reduziert wird. Im find()
Beispiel kann T
immer eindeutig abgeleitet werden.
Im Beispiel forPredicate[1]()
kann T auch eindeutig abgeleitet werden.
Im Beispiel forPredicate[2]()
gibt es Ungewissheit, was T
sein sollte. Wenn das Ergebnis der Methode einem Zieltyp zugeordnet ist, kann T
aus dem Zieltyp ermittelt werden. Sonst ist es ein bisschen Kopf kratzen:
In Java5 / 6 sollte es nicht kompiliert werden. (Nun, ich habe es auf Java 6 getestet und es kompiliert, aber es ist wahrscheinlich ein Fehler, da Java 6 auch forPredicate(p).apply("str")
kompiliert)
Java 7 hat sich ein wenig verbessert, und die neue Regel diktiert das T=Number
. Es funktioniert, aber es fühlt sich eher wie eine Schiedsgerichtsbarkeit an.
Im Idealfall sollten wir uns keine Gedanken über Platzhalter machen. Wenn ich ein Prädikat für meine Ganzzahlen benötige, sollte ich einen Predicate<Integer>
-Parameter deklarieren. Die Tatsache, dass ein Argument Predicate<Number>
auch akzeptabel wäre, ist eine andere Geschichte. Es sollte die Aufgabe des Compilers sein, Predicate<Number>
in Predicate<Integer>
zu konvertieren - wir können es tun, ohne das existierende Java-Generics-System zu überholen, eine neue Konvertierungsregel ist alles, was benötigt wird. Man kann auch eine Konvertierungsbibliothek bereitstellen
Alle convert()
-Methoden können mechanisch generiert werden.
Java 8 macht es ein wenig einfacher. Wir können immer noch nicht
%Vor%Aber wir können
machen %Vor%auch
%Vor% entspricht f = forPredicate[2](pn)
. In Java 8 benötigen wir selten forPredicate()
etc, um zwischen Funktionstypen zu konvertieren.
Tags und Links java generics bounded-wildcard guava