Java 如何获取泛型类型参数?
简单地说:Java 如何获取泛型类型参数?,java,generics,reflection,generic-programming,type-parameter,Java,Generics,Reflection,Generic Programming,Type Parameter,简单地说: 根据@Thomas的指南,我找到了一种获得类java.lang.Integer的方法 首先,我们在测试代码中创建MyClass的匿名子类(需要匿名)。(这很奇怪。为什么它只支持子类?) 它完美地打印了类java.lang.Integer 这不太好,因为测试代码应该模拟实际情况,用户很可能不会继续创建无意义的子类。 这种方法是基于以下思想的。但我真的不知道如何使用它。我尝试了类MyClass扩展了TypeReference。但是我仍然必须创建MyClass的子类,才能拥有TypeRe
根据@Thomas的指南,我找到了一种获得
类java.lang.Integer
的方法
首先,我们在测试代码中创建MyClass
的匿名子类(需要匿名)。(这很奇怪。为什么它只支持子类?)
它完美地打印了类java.lang.Integer
这不太好,因为测试代码应该模拟实际情况,用户很可能不会继续创建无意义的子类。
这种方法是基于以下思想的。但我真的不知道如何使用它。我尝试了类MyClass扩展了TypeReference
。但是我仍然必须创建MyClass
的子类,才能拥有TypeReference.getType()
printsclass java.lang.Integer
请提供帮助,并感谢您的任何意见,因为最佳方法尚未出现
基于上述解决方案的另一个问题是:为什么只有匿名子类可以工作?
公共静态类子MyClass扩展MyClass{}
@试验
公开最终无效测试(){
MyClass myObject=new MyClass(){};//匿名子类
getParamType(myObject);//类java.lang.Integer
MyClass mySubObject=新的子MyClass();//命名的子类
getParamType(mySubObject);//T
}
(
MyClass
和getParamType()
未更改。)Java有一个被误导的特性,名为,专门阻止您这样做
运行时不存在泛型参数信息
相反,您可以手动接受一个
类
,这有点困难,因为Java故意不能这样做(“类型擦除”)
这种变通方法叫做。还有一些关于这方面的线索(如或)。当你有这样的问题时,你应该问自己,没有泛型你会怎么做?因为任何泛型程序都可以转换为没有泛型的等价程序。(这种转换称为类型擦除。)因此,如果没有泛型就无法进行转换,那么也不能使用泛型进行转换 没有泛型的程序如下所示:
public static class SubMyClass<T> extends MyClass<T>{}
@Test
public final void test() {
MyClass<Integer> myObject = new MyClass<Integer>() {}; // Anonymous sub-class
getParamType( myObject ); // class java.lang.Integer
MyClass<Integer> mySubObject = new SubMyClass<Integer>(); // named sub-class
getParamType( mySubObject ); // T
}
要了解
T
的值,您需要通过子类化MyClass在类型定义中捕获它:
public static class MyClass {
ArrayList mArrayList = new ArrayList();
}
@Test
public final void test() {
MyClass myObject = new MyClass();
Integer result = getParamType( myObject ); // how would you implement getParamType()?
}
class MyStringClass扩展了MyClass{}
如果需要,还可以使用匿名类执行此操作:
class MyStringClass extends MyClass<String> {}
MyClass myStringClass=newmyclass{}();
要解析T的值,可以使用:
Class stringType=TypeResolver.resolveRawArgument(MyClass.Class,myStringClass.getClass());
断言stringType==String.class;
谢谢您的回复。“手动接受类”是什么意思?在构造函数中添加一个Class
参数。擦除是一种折衷方法。我不会称之为误导。是不是,我们必须调用MyClass myObject=newmyclass(Integer.class)代码>创建对象时?这是危险的,因为我们可以调用MyClass myObject=newmyclass(String.class)
也是有效的。@如果您将参数声明为类
,则无效。谢谢Thomas!TypeReference
类对我来说是新的。我可以解释为什么TypeReference
可以得到它的T
,因为(1)它是抽象的,因此强制继承,(2)只有Type java.lang.Class.getGenericSuperclass()
可以被强制转换为ParameterizedType
,因此,我们可以使用getActualTypeArguments
?如果有像Type java.lang.Class.getGeneric\uuuuuuuuuuuu Class()
这样的方法,我们可以在那里执行((ParameterizedType)getClass().getGeneric\uuuuuuuuuuuuuu Class())。getActualTypeArguments()
会很棒,不是吗?顺便问一下,为什么Java只有返回类型的“getsuper”方法?回到原来的问题。如何借助TypeReference
获取类java.lang.Integer
?通过newtypereference(){}.getType()
我可以获得java.util.List
(但是这没有用,因为它不是从对象中获得的)。然后我让类MyClass扩展类型引用
并通过myObject.getType()
我只得到T
。谢谢你给我指路。请帮我再深入一点。如果没有泛型,我们怎么才能得到泛型?@midnite:这不是泛型的问题。这是关于程序的逻辑。例如,如果您让MyClass
的构造函数获取一个表示类的Class
类型的参数,并将其存储在类中,那么在擦除之后,您将看到您正在执行MyClass myObject=newmyclass(clazz)代码>,并且您正在类内存储类型为Class
的变量。从这里你可以清楚地看到为什么这样做有效,而你的方法无效。谢谢你的回复。将类
保留为成员字段,我理解它的工作原理。但我不明白相反的意思。就像,有一个成员字段public T mField
之后,我们还可以从mField.getClass()
中检索T
。此外,为什么只有getGenericSuperclass()
而没有getGenericThisclass()
?这似乎不合逻辑。@midnite:泛型只是一种编译时类型检查。这是一种错觉。它实际上并不“存在”。您请求类型参数是因为您在这个幻觉中看到它。我向你展示的是当你剥离幻觉的时候是什么,向你展示你所看到的并不存在,你需要其他东西。要记住的最重要的一点是:当你向一段代码中添加泛型时,它永远不会给你神奇的能力去做在泛型之前你做不到的事情。这就是为什么问你自己如果没有泛型你会怎么做是很有启发性的。
private static final <T> void getParamType(final MyClass<T> _myObject) {
System.out.println( ((ParameterizedType) _myObject.getClass().getGenericSuperclass()).getActualTypeArguments()[0] );
}
public static class SubMyClass<T> extends MyClass<T>{}
@Test
public final void test() {
MyClass<Integer> myObject = new MyClass<Integer>() {}; // Anonymous sub-class
getParamType( myObject ); // class java.lang.Integer
MyClass<Integer> mySubObject = new SubMyClass<Integer>(); // named sub-class
getParamType( mySubObject ); // T
}
public static class MyClass {
ArrayList mArrayList = new ArrayList();
}
@Test
public final void test() {
MyClass myObject = new MyClass();
Integer result = getParamType( myObject ); // how would you implement getParamType()?
}
class MyStringClass extends MyClass<String> {}
MyClass<String> myStringClass = new MyClass<String>{}();
Class<?> stringType = TypeResolver.resolveRawArgument(MyClass.class, myStringClass.getClass());
assert stringType == String.class;