想象一下以下情形:
class MyClass extends OtherClass<String>{
String myName;
//Whatever
}
class OtherClass<T> {
T myfield;
}
而且我分析使用反射专门MyClass的(MyClass.class).getDeclaredFields()
在这种情况下,我会得到下面的字段(和类型,使用的getType()领域的):
myName --> String
myField --> T
我想要得到T,其在运行时知道由于明确的“串”的实际类型的扩展符号,我怎么去获得非遗传型MyField的吗?
编辑解决:
好像答案是“你不能”。 对于那些谁可以看这个问题,后来我推荐使用杰克逊(我想这样做是为了产生JSON)和注解类和字段以这样的方式让杰克逊知道继承层次,并能自动做什么下面的正确答案建议。
这可以通过反射来实现,只是因为你明确地使用String
,否则这些信息将已经失去了应有的类型擦除。
ParameterizedType t = (ParameterizedType) MyClass.class.getGenericSuperclass(); // OtherClass<String>
Class<?> clazz = (Class<?>) t.getActualTypeArguments()[0]; // Class<String>
我发现了一个很好的解释在这里 :
当运行时检查一个参数化类型本身,比如java.util.List的,有没有知道什么类型已经对参数的方式。 这是有道理的,因为类型参数可以设定为在同一个应用程序的所有种类型。 但是,当你检查声明使用参数化类型的方法或字段,你可以在运行时是什么类型的paramerizable类型参数被看到。
简而言之:
你看不到一个类型本身它是什么类型参数的运行时间,但你可以看到它的领域和方法,它被使用和参数。
在代码:
你不能看到T
这里:
class MyClass<T> { T myField; }
你可以看到“ T
”在这里:
class FooClass {
MyClass<? extends Serializable> fooField;
}
在这里,您将能够告诉的类型和类型参数fooField
。 见getGeneric*()
方法的Class
和Method
。
顺便说一句,我经常会看到这样(缩短):
Class fieldArgClass = (Class) aType.getActualTypeArguments()[0];
这是不正确的,因为getActualTypeArguments()
会,常会,返回TypeVariable
而不是阶级-这时候一般是<? extends SomeClass>
<? extends SomeClass>
而不是仅仅<SomeClass>
。 它可以走得更深,试想:
class FooClass {
MyClass<? extends Map<String, List<? extends Serializable>>> fooField;
}
所以,你得到的树Type
秒。 但是,这是一个有点题外话。 请享用 :)
这就是为什么反思是不是一个好主意一个典型的例子。
您可以通过反射程序得到什么仅仅是那些编译器的人的语言选择使可获得的事实。
他们一般没有能力让一切可用的; 他们会有点要保持原始程序文本周围。
所有关于你的代码的其他事实不予提供给reflectee。
造成这种情况的治疗主要是加强语言以外 ,并使用一个工具, 可以提供约代码信息的任意位。 这些工具被称为程序转换系统(PTS) 。
甲PTS解析源代码和建立一个AST的表示它。 一个好的PTW将建立基本持有的一切,以便它可以检查代码(操作员,操作数,标点,注释)的AST。 通常,一个PTS将记录语言的令牌的行/列位置,从而即使布局信息是可用的; 在必要的时候,如果问它极端PTS将记录标记,或至少知道如何阅读原文文件之间的间隙的空白。 这AST在本质上是等同的全文我说是必要的,但在一个更方便的形式来处理。
(具有的PTS另外一个非常好的特性:他们可以修改 AST并重新生成修改后的程序代码,但超出的反映,是,所以我不会在这方面进一步的评论。)。
泛型类型在运行时不知道。 只有编译器知道他们会检查你的程序输入正确,然后将其删除。
在您的特定情况下,调用MyClass.class.getGenericSuperclass()
可以给你所需要的信息,因为一些奇怪的原因,所使用的具体类型继承保持在类描述符时。
马丽娟各地工作在这里 。 这是所谓的“Gafters小工具”的格局。 它是由杰克逊和谷歌库,如番石榴使用。
/ ** *引用泛型类型。 * * @author crazybob@google.com(鲍勃·李)* /
公共抽象类TypeReference {
private final Type type; private volatile Constructor<?> constructor; protected TypeReference() { Type superclass = getClass().getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; } /** * Instantiates a new instance of {@code T} using the default, no-arg * constructor. */ @SuppressWarnings("unchecked") public T newInstance() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { if (constructor == null) { Class<?> rawType = type instanceof Class<?> ? (Class<?>) type : (Class<?>) ((ParameterizedType) type).getRawType(); constructor = rawType.getConstructor(); } return (T) constructor.newInstance(); } /** * Gets the referenced type. */ public Type getType() { return this.type; } public static void main(String[] args) throws Exception { List<String> l1 = new TypeReference<ArrayList<String>>() {}.newInstance(); List l2 = new TypeReference<ArrayList>() {}.newInstance(); }
}
没有直接的方式来获得实际的类型,因为的类型擦除 。 然而,你可以使用下面的方法:
在OtherClass<T>
写入以下抽象方法:
protected abstract class<T> getClazz();
然后在MyClass
,需要实现的方法:
@Override
protected Class<String> getClazz(){
return String.class;
}
那么你可以调用getClazz()
来获取类。