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()
prints
class 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;