Reflexion für Klasse generischer Parameter in Java?

8

Stellen Sie sich das folgende Szenario vor:

%Vor%

Und ich analysiere MyClass unter Verwendung der Reflektion speziell (MyClass.class).getDeclaredFields() , in diesem Fall erhalte ich die folgenden Felder (und Typen, benutze getType () des Feldes):

%Vor%

Ich möchte den tatsächlichen Typ für T erhalten, der zur Laufzeit aufgrund des expliziten "String" in der extends-Notation bekannt ist. Wie gehe ich vor, um den nicht-genetischen Typ von myField zu erhalten?

EDIT BEHOBEN:

Scheint so, als wäre die Antwort "du kannst nicht". Für diejenigen, die sich diese Frage später ansehen sollten, würde ich empfehlen, Jackson zu verwenden (ich habe versucht, JSON zu generieren) und Ihre Klassen und Felder so zu kommentieren, dass Jackson die Vererbungshierarchie kennt und automatisch was tun kann die richtige Antwort unten vorgeschlagen.

    
Sam Stern 22.06.2012, 22:07
quelle

5 Antworten

18

Dies kann nur mit Reflektion erreicht werden, weil Sie String explizit verwendet haben, sonst wäre diese Information durch Löschen des Typs verloren gegangen.

%Vor%     
Jeffrey 22.06.2012, 22:39
quelle
3

Ich fand eine schöne Erklärung hier :

  

Bei der Laufzeitprüfung eines parametrisierbaren Typs wie java.util.List kann nicht festgestellt werden, um welchen Typ es sich handelt. Dies ist sinnvoll, da der Typ für alle Arten von Typen in derselben Anwendung parametrisiert werden kann. Wenn Sie jedoch die Methode oder das Feld untersuchen, das die Verwendung eines parametrisierten Typs deklariert, können Sie zur Laufzeit sehen, für welchen Typ der parametrisierbare Typ parametrisiert wurde.

Kurz gesagt:

Sie können auf einem Typ selbst nicht sehen, welchen Typ er für eine Laufzeit parametrisiert hat, aber Sie können ihn in Feldern und Methoden sehen, wo er verwendet und parametrisiert wird.

Im Code:

Sie können T hier nicht sehen:

%Vor%

Sie können die " T " hier sehen:

%Vor%

Hier könnten Sie die Typ- und Typparameter von fooField angeben. Siehe getGeneric*() Methoden von Class und Method .

Übrigens sehe ich das oft (verkürzt):

%Vor%

Dies ist nicht korrekt, weil getActualTypeArguments() TypeVariable anstelle von class zurückgeben kann und oft auch zurückgibt - das ist, wenn das generische% <? extends SomeClass> ist und nicht nur <SomeClass> . Es kann tiefer gehen, stellen Sie sich vor:

%Vor%

Sie erhalten also einen Baum von Type s. Aber das ist ein bisschen off-topic. Viel Spaß mit:)

    
Ondra Žižka 20.07.2016 12:32
quelle
0

Generische Typen sind nicht zur Laufzeit bekannt. Nur der Compiler weiß von ihnen, prüft, ob Ihr Programm korrekt eingegeben wurde, und entfernt sie dann.

In Ihrem speziellen Fall könnte der Aufruf von MyClass.class.getGenericSuperclass() Ihnen die Informationen liefern, die Sie benötigen, denn aus irgendeinem seltsamen Grund werden die konkreten Typen, die beim Erben verwendet werden, im Klassendeskriptor gespeichert.

    
Jochen 22.06.2012 22:15
quelle
0

Dies ist ein klassisches Beispiel dafür, warum Reflexion keine gute Idee ist.

Was Sie von einem Programm durch Reflektion erhalten können, sind nur die Fakten, die die Compiler-Leute für die Sprache zur Verfügung gestellt haben.

Und sie können es sich im Allgemeinen nicht leisten, alles zur Verfügung zu stellen; sie müssten irgendwie den rohen Programmtext herum behalten.

Alle anderen Fakten über Ihren Code stehen dem Reflectee somit nicht zur Verfügung.

Das Problem besteht darin, außerhalb der Sprache zu springen und ein Werkzeug zu verwenden, das beliebige Informationen über den Code liefern kann. Solche Werkzeuge heißen Programmtransformationssysteme (PTS) .

Ein PTS analysiert den Quellcode und erstellt einen AST, der ihn darstellt. Eine gute PTW wird einen AST erstellen, der im Wesentlichen alles über den Code enthält (Operatoren, Operanden, Interpunktion, Kommentare), so dass er inspiziert werden kann. Normalerweise zeichnet ein PTS die Zeilen- / Spaltenposition von Sprachtokens auf, so dass sogar Layoutinformationen verfügbar sind. Extreme PTS zeichnet den Leerraum in den Lücken zwischen Token auf oder weiß zumindest, wie die Originaldatei bei Bedarf zu lesen ist. Dieser AST entspricht im Wesentlichen dem vollständigen Text, von dem ich sagte, dass er notwendig wäre, aber in einer bequemeren Form, um ihn zu verarbeiten.

(PTSs haben eine andere sehr nette Eigenschaft: Sie können den AST modifizieren und den Code für das modifizierte Programm neu generieren. Aber das ist über die Reflexion hinaus, deshalb werde ich diesen Aspekt nicht weiter kommentieren) .

    
Ira Baxter 20.07.2016 13:02
quelle
-5

Wegen des Typs Erasure gibt es keinen direkten Weg, den eigentlichen Typ zu erhalten . Sie können jedoch folgendermaßen vorgehen:

Schreiben Sie in Ihrer OtherClass<T> die folgende abstrakte Methode:

%Vor%

Dann in MyClass , implementieren Sie die Methode:

%Vor%

Dann können Sie getClazz() aufrufen, um die Klasse zu erhalten.

    
Chun 22.06.2012 22:14
quelle

Tags und Links