Angenommen, ich habe eine Methode "mixen", die zwei Listen von möglicherweise unterschiedlichen Typen T und S nimmt und eine einzelne Liste zurückgibt, die die Elemente von beiden enthält. Für type-safety möchte ich angeben, dass die zurückgegebene Liste vom Typ R ist, wobei R ein für T und S gemeinsamer Supertyp ist. Beispiel:
%Vor%Um dies zu spezifizieren, könnte ich die Methode als
deklarieren %Vor% Aber was, wenn ich mix
eine Instanzmethode anstelle von statisch in der Klasse List2<T>
machen möchte?
schattiert die <T>
für die Instanz von List2
, das ist also nicht gut.
löst das Schattenproblem, wird aber vom Compiler nicht akzeptiert
%Vor% wird vom Compiler zurückgewiesen, da in einer benannten Variablen (nur in ? super X
-Ausdrücken verwendete) niederwertigere Platzhalter nicht gespeichert werden können
Ich könnte die Argumente in die Klasse selbst verschieben, wie zum Beispiel List2<R, T extends R, S extends R>
, aber die Typinformation hat wirklich nichts mit der Instanzebene zu tun, da sie nur für einen Methodenaufruf verwendet wird Objekt jedes Mal, wenn Sie die Methode für verschiedene Argumente aufrufen möchten.
Soweit ich das beurteilen kann, gibt es keine Möglichkeit, dies mit Generika zu tun. Das Beste, was ich tun kann, wäre, ein rohe List2
zurückzugeben und es auf der Callsite zu präsentieren, wie zuvor Generika eingeführt wurden. Hat jemand eine bessere Lösung?
Wie in der Frage und in den Kommentaren erwähnt, wäre die folgende Signatur ideal:
%Vor% Aber natürlich ist R super T
von der Sprache nicht erlaubt (Anmerkung dass die Antwort von polygeneLubricants auf den verknüpften Post falsch ist - es gibt Anwendungsfälle für diese Syntax, wie Ihre Frage zeigt.
Es gibt keine Möglichkeit, hier zu gewinnen - Sie haben nur eine von mehreren Problemumgehungen zur Auswahl:
mix
als statische Methode. Dies ist eigentlich eine vernünftige Option, es sei denn, sie muss aus polymorphismusbedingten Gründen Teil der Klasse sein, oder Sie planen, dass mix
eine so häufig verwendete Methode ist, von der Sie denken, dass sie statisch nicht akzeptabel ist. mix
, die übermäßig restriktiv ist, ab und dokumentieren Sie, dass bestimmte unkontrollierte Umwandlungen seitens des Aufrufers erforderlich sind. Dies ist vergleichbar mit dem Guava %Co_de% musste tun. Aus der Dokumentation dieser Methode: Hinweis zu Generika: Die Signatur
%Vor%Optional.or
ist zu restriktiv. Die ideale Signaturpublic T or(T defaultValue)
ist jedoch kein zulässiges Java. Daher sind einige sinnvolle Operationen mit Untertypen Kompilierungsfehler:Als Workaround ist es immer sicher,
%Vor%public <S super T> S or(S)
aufOptional<? extends T>
zu übertragen. Casting [die obigeOptional<T>
-instanz] zuOptional
(wobeiOptional<Number>
der gewünschte Ausgabetyp ist) löst das Problem:
Leider ist es nicht immer sicher, Number
auf List2<? extends T>
zu übertragen. Wenn beispielsweise List2<T>
in List2<Integer>
umgewandelt wird, kann List2<Number>
zu etwas hinzugefügt werden, das nur Double
s enthält und zu unerwarteten Laufzeitfehlern führt. Die Ausnahme wäre, wenn Integer
unveränderlich wäre (wie List2
), aber das scheint unwahrscheinlich.
Trotzdem könnten Sie mit solchen Abgüssen durchkommen, wenn Sie vorsichtig waren und dokumentierten, unsicheren Code mit Erklärungen. Angenommen Optional
hatte die folgende Signatur (und die Implementierung zum Spaß):
Dann haben Sie vielleicht die folgende Aufrufseite:
%Vor% Auch hier wird ein Settlement für eine statische mix
sauberer und hat kein Risiko für die Typ-Sicherheit. Ich würde sicherstellen, dass ich sehr gute Gründe habe, es nicht so zu halten.
Ich bin mir in Ihrer Frage nicht sicher, ob Sie bereits wissen, welchen Supertyp diese Unterklassen erweitern, oder Sie möchten eine vollständig generische Methode, bei der Sie zwei Subtypen einer bestimmten Oberklasse übergeben.
Im ersten Fall habe ich kürzlich etwas Ähnliches gemacht, mit einer abstrakten Klasse und mehreren Subtypen:
%Vor%Der letztere Fall ist viel komplizierter. Ich würde vorschlagen, dass Sie Ihr Design überdenken, da es viel sinnvoller ist, wenn die Mix-Methode in der Superklasse oder in einer Klasse ist, die die Superklasse und ihre Subtypen kennt, da Sie eine Liste der Superklasse zurückgeben >
Wenn Sie das wirklich tun möchten, müssten Sie List2 zu List2 umgestalten und folgendermaßen vorgehen:
%Vor%Tags und Links java generics bounded-wildcard