Java中泛型参数类的反射?
想象一下以下场景:
class MyClass extends OtherClass<String>{
String myName;
//Whatever
}
class OtherClass<T> {
T myfield;
}
我正在使用反射分析MyClass,特别是(MyClass.class).getDeclaredFields()
,在本例中,我将使用字段的getType()获得以下字段(和类型):
myName --> String
myField --> T
我想得到T的实际类型,这在运行时是已知的,因为extends表示法中有显式的“String”,如何获得myField的非遗传类型
编辑已解决:
答案似乎是“你不能”。对于那些稍后可能会看到这个问题的人,我建议使用Jackson(我试图这样做是为了生成JSON)并以这样的方式注释类和字段,以便Jackson知道继承层次结构,并能够自动执行下面正确答案所建议的操作
# 1 楼答案
这只能通过反射实现,因为您显式地使用了
String
,否则由于类型擦除,此信息将丢失# 2 楼答案
围绕here开展大型工作。它被称为“Gafters Gadget”模式。它被jackson和谷歌图书馆如guava使用
/** *引用泛型类型。 * *@作者crazybob@google.com(李国宝) */
^{pr1}$}
# 3 楼答案
我找到了一个很好的解释here:
简言之:
您无法在类型本身上看到它被参数化到运行时的类型,但可以在使用和参数化它的字段和方法中看到它
代码:
您无法在此处看到
T
:您可以在这里看到“
T
”:在这里,您可以告诉}和{}的{}方法
fooField
的类型和类型参数。 参见{顺便说一下,我经常看到这个(缩写):
这是不正确的,因为
getActualTypeArguments()
可能而且通常会返回TypeVariable
而不是类-这时泛型是<? extends SomeClass>
,而不是仅仅<SomeClass>
。它可以更深入,想象一下:所以你得到了一个
Type
树。但这有点离题了。享受:)# 4 楼答案
泛型类型在运行时不是已知的。只有编译器知道它们,检查程序的类型是否正确,然后删除它们
在您的特定情况下,调用
MyClass.class.getGenericSuperclass()
可能会为您提供所需的信息,因为出于某种奇怪的原因,继承时使用的具体类型保留在类描述符中# 5 楼答案
这是一个典型的例子,说明了为什么反射不是一个好主意
通过反射,您可以从程序中获得的只是该语言的编译器人员选择提供的事实强>
他们通常负担不起提供一切的费用;他们必须保留原始的程序文本
因此,反射对象无法获得有关代码的所有其他事实
解决这一问题的方法是在语言之外使用工具,该工具可以提供有关代码的任意信息。这种工具称为Program Transformation Systems (PTS)
PTS解析源代码并构建表示源代码的AST。一个好的PTW将构建一个AST,该AST基本上包含代码的所有内容(运算符、操作数、标点符号、注释),以便对其进行检查。通常情况下,PTS会记录语言标记的行/列位置,因此即使布局信息可用;extreme-PTS将在令牌之间的间隙中记录空格,或者至少知道如何在必要时读取原始文本文件(如果被询问)。这个AST在本质上等同于我所说的全文,这是必要的,但以一种更方便的形式进行处理
(PTS还有一个非常好的特性:它们可以修改AST并为修改后的程序重新生成代码。但这超出了反射的范围,所以我不会在这方面作进一步的评论)
# 6 楼答案
由于Type Erasure的原因,无法直接获取实际类型。但是,您可以使用以下方法:
在
OtherClass<T>
中,编写以下抽象方法:然后在
MyClass
中,实现以下方法:然后可以调用
getClazz()
来获取类