Verwenden Sie generic, um einen allgemeinen Supertyp in Java zu speichern

9

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?

%Vor%

schattiert die <T> für die Instanz von List2 , das ist also nicht gut.

%Vor%

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?

    
Matt G 18.08.2013, 21:12
quelle

2 Antworten

4

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:

  • Verwenden Sie eine Signatur mit Rohtypen. Tun Sie das nicht.
  • Behalte 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.
  • Setzen Sie sich mit der Signatur von 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 Optional.or ist zu restriktiv. Die ideale Signatur public T or(T defaultValue) ist jedoch kein zulässiges Java. Daher sind einige sinnvolle Operationen mit Untertypen Kompilierungsfehler:

%Vor%      

Als Workaround ist es immer sicher, public <S super T> S or(S) auf Optional<? extends T> zu übertragen. Casting [die obige Optional<T> -instanz] zu Optional (wobei Optional<Number> der gewünschte Ausgabetyp ist) löst das Problem:

%Vor%

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ß):

%Vor%

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.

    
Paul Bellora 20.08.2013 03:55
quelle
0

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%     
Tarek 22.01.2014 22:34
quelle

Tags und Links