Rekursives generisches und fließendes Interface

8

tl; dr

Der Versuch, eine hierarchisch fließende Schnittstelle zu implementieren, so dass ich Knoten untergeordnete Klassen kombinieren kann, während auch die Klasse standalone, aber get type Parameter ist nicht innerhalb seiner gebundenen Fehler.

Details

Ich versuche eine Lösung zu finden, damit ich etwas so erstellen kann, dass ich so etwas wie machen kann:

%Vor%

während es auch möglich ist:

%Vor%

Ich habe mich mit verschiedenen Strategien vertraut gemacht, konnte aber die beschriebene Flexibilität nicht erreichen.

Mein aktueller Versuch verwendet die folgenden Klassen:

%Vor%

Die Fehler, die ich sehe, sind häufig:

  

Animal.java:4: type parameter Animal ist nicht innerhalb seiner gebundenen privaten Katze;   Animal.java:5: type Parameter Animal ist nicht in seinem gebundenen privaten Hund Hund;

Angewendet auf alle ähnlichen Referenzen und auch auf meinen Beispiel-Wunschfall bezogen:

  

kann kein Symbol finden   Symbol: Methode Hund ()   Ort: Klasse Base.dog ()

Ich habe versucht, die folgenden Lösungen zu verwenden, die ähnliche Probleme anzugehen schienen, aber ohne Erfolg, daher ist jede Unterstützung willkommen.

Referenzen

SS44 10.10.2014, 17:04
quelle

7 Antworten

3

Der folgende Code scheint gut zu funktionieren und benötigt keine @SuppressWarnings . Das Schlüsselkonzept, das Sie verstehen sollten, ist, dass Ihr T -Parameter tatsächlich die Klasse des übergeordneten Objekts Ihres Objekts ist, aber das übergeordnete Element T könnte alles sein. Also statt T extends Base<T> willst du T extends Base<?> .

Die Ausgabe ist:

%Vor%

... was ich für richtig halte, obwohl Sie vielleicht Ihre Dog.chacesCar() -Methode ändern möchten, damit cat drinks milk nicht ausgegeben wird! Außerdem sollte es chases nicht chaces sein.

Hoffe, das hilft!

%Vor%

Testcode:

%Vor%     
Constantinos 15.10.2014, 10:00
quelle
3

Das Beste, was ich herausgefunden habe, ist folgendes:

%Vor%

Mit der folgenden Basisklasse:

%Vor%

Wenn Sie backRef ab Typ T deklarieren, sind die anderen Klassen nicht erlaubt, da sie keine Unterklassen voneinander sind. Sie müssen also einen anderen Typ angeben, aber da dieser Typ kontextabhängig ist (einmal sein Cat, Einmal sein Hund) Ich sehe keine Alternative, um einen Hinweis zu geben.

Ich habe eine Lösung gefunden:

%Vor%

Wie jemand vorgeschlagen hat, fügen wir einen zusätzlichen Typ für den Eltern hinzu.

Jetzt die Basisklassen:

%Vor%

Wie Sie sehen, legt Cat klar fest, welchen Basistyp es verwenden soll. Jetzt für den Menschen, der den Typ abhängig vom Kontext ändern kann:

%Vor%

}

Human gibt ein zusätzliches generisches Element an, das der Aufrufer (Cat, Dog) in seiner Methode findHuman () angibt.

    
morpheus05 14.10.2014 13:59
quelle
2

Das haben wir an einem unserer Projekte gemacht:

%Vor% %Vor%

Wenn child eine eigene Unterklasse hätte, wäre dies:

%Vor%     
Pavel Horal 14.10.2014 13:41
quelle
1

In dieser Zeile:

%Vor%

Der Compiler behandelt den zweiten Typparameter als eine konkrete Klasse. Angenommen, Sie haben diese Zeile durch Folgendes ersetzt:

%Vor%

'Double' ist eine konkrete Klasse. Wenn der Compiler dies durchsucht, kann er den Unterschied zwischen Ihrem T und Double nicht erkennen und behandelt sie beide als konkrete Klasse und nicht als Typ-Parameter. Die einzige Möglichkeit, dem Compiler mitzuteilen, dass T ein Typparameter ist, lautet folgendermaßen:

%Vor%

Ich hoffe, dass dies Ihre Frage beantwortet (oder zumindest relevant ist).

Bearbeiten Post wurde bearbeitet, während ich tippte, also denke ich, dass diese Antwort nicht mehr relevant ist.

    
Tetramputechture 14.10.2014 13:43
quelle
1

Ihr Problem ist, dass die Methode den Elternteil zurückgeben soll, aber der Elternteil ist nicht unbedingt ein T, sondern nur eine Basis. Und das andere Problem ist, dass die Methode done immer die gleiche Klasse zurückgeben sollte, unabhängig von der Klasse.

Aber hier ist eine kleine Variation Ihrer vorgeschlagenen Klassen. Zuerst für Base , das seine konkrete Klasse und ihr konkretes Elternteil deklariert:

%Vor%

Dadurch werden die abgeleiteten konkreten Klassen:

%Vor%

Damit könnte ich ohne Fehler oder Warnung schreiben:

%Vor%

Beachten Sie jedoch, dass ich die Aufrufe von done durch animals ersetzen musste.

Bearbeiten:

Ich habe eine neue Klasse CatOrDog hinzugefügt, um die Human Verarbeitung zu faktorisieren. Da das übergeordnete Element eines Human ein Farm ist, initialisiere ich das neue human mit einem korrekten Elternelement, falls es existiert. Auf diese Weise kompiliert nicht nur die oben genannten Quellen ohne Fehler oder Warnung, sondern es läuft auch ohne Probleme und es wird gedruckt:

%Vor%     
Serge Ballesta 14.10.2014 14:40
quelle
0

Es gibt keinen "sicheren" Weg, dies zu tun, aber dies sollte kompilieren:

%Vor%     
Sean Patrick Floyd 14.10.2014 13:47
quelle
0

Sie können auch mit Interfaces spielen, so dass Sie mehrfache Vererbung fälschen können. Ein bisschen ausführlich, aber es gibt keine gefährliche Casting, und ich finde es ganz verständlich.

Definieren Sie die verfügbaren Methoden:

%Vor%

Sie müssen möglicherweise mehrere Methoden in einer Schnittstelle haben, aber ich habe diesen Bedarf noch nicht erfüllt. Zum Beispiel, wenn Sie Arten von meow s gehabt hätten:

%Vor%

Definieren Sie die Ausgabetypen:

Farm liefert Animal oder Human :

%Vor%

Animal liefert Cat , Dog oder Done :

%Vor%

Cat liefert Meow , FindsHuman oder Done :

%Vor%

Dog liefert Bark , ChacesCar , FindsHuman oder Done :

%Vor%

Human liefert SayHello oder Done :

%Vor%

Implementieren Sie einfach die * Out-Schnittstellen:

%Vor%

Diese Implementierungen würden auch ohne die Schnittstellen funktionieren: Entfernen Sie implements *Out , @Override s und ersetzen Sie alle *Out durch * (z. B. AnimalOut by Animal ). Das heißt, es ist einfacher, mit den Schnittstellen zu warten: Aktualisieren Sie sie einfach und beheben Sie Ihre Kompilierungsfehler. Es ist auch einfacher, DSL-Lösungen mit Schnittstellen zu finden (wie Sie sehen können), und manchmal sind sie einfach notwendig.

Demo:

%Vor%

Drucke:

%Vor%     
sp00m 14.10.2014 14:34
quelle