Sagen wir, ich habe eine einfache Klasse
%Vor%Und die Handler-Schnittstelle zur Verarbeitung der Kindklassen von MyObject
%Vor%Angenommen, ich habe BigObjects und SmallObjects (beide erweitern MyObject) und ich möchte separate Handler für sie haben. Also, ich erstelle zwei Schnittstellen von MyObjectHandler mit bestimmten Generika.
%Vor% Nun stellen wir uns vor, dass wir AbstractHandlerChain<...>
abstract class erstellt haben. Also können wir die BigHandlerChain-Klasse erstellen und unsere BigHandler (und dasselbe mit SmallHandlerChain) injizieren.
Die Frage: Ist es möglich, für diesen Fall den perfekten AbstractHandlerChain zu erstellen?
das funktioniert, aber in handler.handle(objects)
Ich bekomme Unchecked call to 'handle(List<V>)' as a member of raw type 'MyObjectHandler'
, also sollte ich @SuppressWarnings("unchecked")
hinzufügen, das ist nicht sehr gut.
Funktioniert nicht. In handler.handle(objects)
bekomme ich handle (java.util.List<capture<? extends MyObject>>) cannot be applied to (java.util.List<V>)
. Warum kann ich in diesem Fall keine Objekte an Handler übergeben? Wildcard erweitert MyObject und V erweitert MyObject. Ist es nicht genug?
das funktioniert, aber in diesem Fall sollte ich BigHandlerChain als class BigHandlerChain extends AbstractHandlerChain<BigObjectHandler, BigObject>
definieren. Aber BigObjectHandler
enthält bereits Informationen über Klassen, die von ihm verarbeitet werden können, also ist es eine doppelte Information.
Hier ist eine Lösung, die ich von Java erwarte, aber es funktioniert nicht! Ich kann keine Klasse wie diese ...class HandlerChain<T extends MyObjectHandler<V extends MyObject>
deklarieren. Warum kann ich nach MyObjectHandler Platzhalter verwenden, kann diese Konstruktion aber nicht verwenden?
Lösung 1
Das funktioniert, aber in handler.handle (objects) bekomme ich einen unmarkierten Aufruf von 'handle (List)' als ein Element vom Rohtyp 'MyObjectHandler', also sollte ich @SuppressWarnings ("unchecked") hinzufügen, das nicht ist sehr gut.
Tatsächlich, weil MyObjectHandler
ein generischer Typ ist, aber Sie geben nicht den Typ dafür in HandlerChain
's Typparameter ein.
Lösung 2
Funktioniert nicht. In handler.handle (objects) bekomme ich handle (java.util.List & gt;) kann nicht auf (java.util.List) angewendet werden. Warum kann ich in diesem Fall keine Objekte an Handler übergeben? Wildcard erweitert MyObject und V erweitert MyObject. Ist es nicht genug?
Nein. ? extends MyObject
sagt im Grunde, dass es für einen nicht spezifizierten Typ ist, der MyObject
erweitert, aber du sagst nicht welche. Sie könnten eine Klasse public class BigHandlerChain<BigObjectHandler>
erstellen, aber eine Liste von SmallObject
Instanzen an doChain
.
Lösung 3
Dies funktioniert, aber in diesem Fall sollte ich BigHandlerChain als Klasse definieren. BigHandlerChain erweitert AbstractHandlerChain. Aber BigObjectHandler enthält bereits Informationen über Klassen, die von ihm gehandhabt werden können, also ist es Informationsduplizierung.
Tatsächlich gibt es hier einige doppelte Informationen, aber wenn generische Typen wie diese zusammengesetzt werden, wird das wahrscheinlich passieren. Da Ihre doChain
-Methode auf einem bestimmten Typ ausgeführt wird, muss angegeben werden, was dieser Typ tun kann. Sehen Sie es so, als würden Sie BigObject
lists behandeln und die von Ihnen bereitgestellten Handler müssen in der Lage sein, BigObjects zu handhaben.
Lösung 4
Hier ist eine Lösung, die ich von Java erwarte, aber es funktioniert nicht! Ich kann Klasse nicht so deklarieren ... Klasse HandlerChain. Warum kann ich nach MyObjectHandler Platzhalter verwenden, kann diese Konstruktion aber nicht verwenden?
Das Problem ist, dass V
auf einen bestimmten Typ und nicht auf einen Platzhalter hinweist, also müssen Sie angeben, was V ist.
Mit anderen Worten, Ihre Lösung 3 ist trotz einiger Duplikate der richtige Ansatz. Leider wirst du mehr davon in Java sehen. Getter / Setter sind wohl unnötige Boilerplates, wenn bestimmte Modifikationsschlüsselwörter auf den Feldern dasselbe erreichen könnten (wie in Ruby).
Beachten Sie jedoch, dass Sie, wenn Sie public abstract class HandlerChain<T extends MyObjectHandler<V>, V extends MyObject>
angeben, angeben, dass die Kette nur für einen bestimmten Typ von MyObjectHandler
geeignet ist. Da ich denke, dass Sie wahrscheinlich eine Kette von verschiedenen Handlern benötigen, die alle in der Lage sind, die gleichen Objekttypen zu behandeln, sollten Sie nur diesen Objekttyp angeben:
Der Handler muss nicht generisch sein, nur das Objekt:
%Vor%Dies ermöglicht:
%Vor% EDIT: Wenn Sie die Lösung von G_H und meine vergleichen, ist der einzige Unterschied, dass G_H List<? extends MyObjectHandler<V>>
verwendet. Auf diese Weise können Sie eine Liste übergeben, bei der der deklarierte Elementtyp spezifischer als nur MyObjectHandler<V>
ist. Ich denke, es ist unwahrscheinlich, dass Sie das brauchen werden, aber Sie können diese zusätzliche Flexibilität auch für den Fall nutzen.
Fixing Solution 4 ist so einfach: Der Java-Compiler erwartet, dass die Wildcards zusammen deklariert werden und dann verwendet werden:
%Vor%Tags und Links java inheritance generics