Mit dem folgenden Code-Skelett kann festgestellt werden, dass die Eigenschaft foo
tatsächlich vom Typ String
?
Die tatsächliche Ausgabe ist
foo der Klasse java.lang.Object
TypeVariable: T-Klasse java.lang.Object
Edit: Ich hätte erwähnen sollen, dass ich über das Löschen von Typen Bescheid weiß und dass die Methode tatsächlich ein Objekt auf der Bytecodeebene zurückgibt. Die Metadaten zu generischen Typen stehen jedoch in der Klassendatei zur Verfügung und können wie im Beispielcode durch Reflektion abgefragt werden. Hier ist ein weiteres Snippet, das zeigt, dass SubBean tatsächlich einen Typparameter vom Typ String hat:
%Vor%Ausgabe:
Klasse java.lang.String
Die Frage bleibt dann, wie verbinde ich dieses tatsächliche Typargument mit der Typvariablen? Wenn ich weiß, dass es nur einen Typparameter gibt, ist das einfach, aber ich möchte, dass dieser Code auch für Beans mit mehreren generischen Typparametern funktioniert.
Solange die Laufzeitklasse des Objekts den Wert des Typparameters bestimmt, können Sie dessen tatsächlichen Wert ableiten, indem Sie die Parameter des formalen Typs rekursiv durch die tatsächlichen ersetzen, die Sie aus Class.getGenericSuperClass () erhalten haben:
%Vor%Testcode:
%Vor%Wenn andererseits die Klasse den Wert des Typparameters nicht bestimmt, müssen Sie Ihr Bean erweitern, um das Klassenobjekt für den eigentlichen Typparameter zur Laufzeit auf andere Weise, z. indem Sie:
%Vor%Ich habe eine Lösung für den Fall gefunden, dass es eine Hierarchie mit einem einzigen Super gibt Klasse (abgesehen von Object), die auch funktioniert, wenn es mehrere Typparameter für die Superklasse gibt.
Funktioniert immer noch nicht für tiefere Hierarchien oder bei der Implementierung von generischen Schnittstellen. Auch ich möchte eine Bestätigung, dass dies tatsächlich dokumentiert ist und sollte funktionieren.
%Vor%...
%Vor%Ausgabe:
bar der Klasse java.lang.Object
Übereinstimmung: B: Klasse java.lang.Integer
foo der Klasse java.lang.Object
Übereinstimmung: F: Klasse java.lang.String
Qux der Klasse java.lang.Object
Übereinstimmung: Q: X
Ich muss noch einige Tests schreiben, um zu entscheiden, was ich mit dem letzten Fall tun soll:)
Sie können den Laufzeittyp von generic mit Hilfe von dieser Hack . Code aus der Verknüpfung extrahiert.
%Vor%Java-Generatoren haben während der Kompilierung eine Art der Löschung. Zur Laufzeit ist es nicht möglich, den Typ von T zu ermitteln, der beim Kompilieren vorhanden war.
Hier ist ein Link: Tipp löschen
Leider ist Typ Löschung in Kraft.
Obwohl die SubBean einen festen String-Typ für diesen ivar und diese Methoden haben sollte, weil der type-Parameter für SuperBean
zur Kompilierungszeit bekannt ist, funktioniert das leider nicht so. Der Compiler erstellt keine String
-ige Version von SuperBean
zur Kompilierzeit, von der SubBean
abgeleitet werden kann - es gibt nur eine (vom Typ gelöschte) SuperBean
SubBean
möglicherweise die Superklassenmethode mit der typspezifischen Version überschreiben kann und BeanInfo dann das zurückgibt, was Sie für die Methoden erwarten:
Update: Das obige funktioniert nicht. Beachten Sie diese Information, die @ Jörn Horstmann in den Kommentaren posten:
Dies scheint nicht zu funktionieren, da der Introspector immer noch eine Lese-Methode vom Typ Object zurückgibt. Darüber hinaus scheint dies eine generierte Bridge-Methode zu sein ( Ссылка ), was bedeutet, dass ich vielleicht in < a href="http://bugs.sun.com/view_bug.do?bug_id=6788525"> bugs.sun.com/view_bug.do?bug_id=6788525 wenn ich auf Anmerkungen zu dieser Methode zugreifen möchte.
Eine weitere hässliche Variante der obigen Problemumgehung ist das Aliasing der Eigenschaft:
%Vor% SubBean
hat jetzt eine eindeutige Eigenschaft FooItem
, die ein Alias für die ursprüngliche SuperBean
Eigenschaft Foo
ist.
Leider nein:
Generics werden durch Typ-Löschen implementiert: generische Typ-Informationen sind nur zur Kompilierzeit vorhanden, nach denen sie vom Compiler gelöscht werden. Der Hauptvorteil dieses Ansatzes besteht darin, dass er eine vollständige Interoperabilität zwischen generischem Code und Legacy-Code bietet, der nicht parametrisierte Typen verwendet (die technisch als unformatierte Typen bekannt sind). Die Hauptnachteile bestehen darin, dass Parametertypinformationen zur Laufzeit nicht verfügbar sind und dass automatisch generierte Umwandlungen fehlschlagen können, wenn sie mit fehlerhaftem Legacy-Code zusammenarbeiten. Es gibt jedoch eine Möglichkeit, eine garantierte Laufzeittypsicherheit für generische Sammlungen selbst dann zu erreichen, wenn sie mit schlechtem altem Code interoperieren.
Wie aus Ссылка
zitiert Hier ist der Bytecode von SuperBean
:
Wie Sie sehen, sind sowohl der Getter als auch der Setter vom Typ java.lang.Object. Introspector verwendet Getters und Setter, um den PropertyDescriptor zu generieren (Felder werden ignoriert), sodass die Eigenschaft den generischen Typ von T nicht kennen kann.
Tags und Links java generics introspection javabeans