如何获取通用类型参数?

只是:

public static class MyClass { // i don't want to keep an instance of T, if it is not necessary. // and it is not nice, not neat. // Or, let's say, the member are in the form of : ArrayList mArrayList = new ArrayList(); // the problem of getting the generic type parameter is still present. } @Test public final void test() { MyClass myObject = new MyClass(); getParamType( myObject ); } private static final  void getParamType(final MyClass _myObject) { System.out.println(_myObject.getClass().getTypeParameters()[0]); // T System.out.println(((T) new Object()).getClass()); // class java.lang.Object } 

如何让代码打印class java.lang.Integer

我知道很多stackoverflow线程正在询问(和回答)这个问题。 但他们无法解决这个问题。

  • 我不知道为什么有些人需要调用getGenericSuperclass() – 因为在这个简单的情况下没有涉及inheritance。
  • 我也不能将它转换为ParameterizedType

 System.out.println((ParameterizedType) _myObject.getClass()); // Compile Error: Cannot cast from Class to ParameterizedType System.out.println((ParameterizedType) _myObject.getClass().getGenericSuperclass()); // Runtime Exception: java.lang.ClassCastException 

基于@Thomas的指南,我找到了一种获取class java.lang.Integer 的解决方法。

首先,我们在测试代码中创建一个匿名 (它需要是匿名的) MyClass子类。 (这很奇怪。为什么它只支持子类?)

 @Test public final void test() { MyClass myObject = new MyClass() {}; // Anonymous sub-class getParamType( myObject ); } 

然后我们可以使用getGenericSuperclass()方法获取一个Type然后将其转换为ParameterizedType ,然后使用getActualTypeArguments()

 private static final  void getParamType(final MyClass _myObject) { System.out.println( ((ParameterizedType) _myObject.getClass().getGenericSuperclass()).getActualTypeArguments()[0] ); } 

它完美地打印class java.lang.Integer

不是很好,因为测试代码应该模拟实际情况,用户很可能不会继续创建无意义的子类。

此方法基于TypeReference类的思想。 但我真的不知道如何使用它。 我试过class MyClass extends TypeReference 。 但我仍然需要创建MyClass子类,让TypeReference.getType()打印出class java.lang.Integer

请帮助,并感谢任何输入,因为最好的方法尚未到来。


基于上述解决方法的另一个问题:为什么只有匿名子类有效?

 public static class SubMyClass extends MyClass{} @Test public final void test() { MyClass myObject = new MyClass() {}; // Anonymous sub-class getParamType( myObject ); // class java.lang.Integer MyClass mySubObject = new SubMyClass(); // named sub-class getParamType( mySubObject ); // T } 

MyClassgetParamType()不变。)

这有点困难,因为Java故意不能这样做(“类型擦除”)。

解决方法称为超类型令牌 。 SO上也有一些线索(就像这一个或那个 )。

当你有这样的问题时,你应该问问自己,如果没有generics,你会怎么做? 因为任何generics程序都可以转换为没有generics的等效程序。 (这种转换称为类型擦除。)因此,如果没有Generics就无法做到,那么你也无法使用Generics。

没有Generics的程序看起来像这样:

 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()? } 

Java有一个名为Type Erasure的误导function,专门阻止你这样做。

运行时不存在通用参数信息。

相反,您可以手动接受Class

要了解T的值,您需要通过子类化MyClass在类型定义中捕获它:

 class MyStringClass extends MyClass {} 

如果需要,您还可以使用匿名类执行此操作:

 MyClass myStringClass = new MyClass{}(); 

要解析T的值,可以使用TypeTools :

 Class stringType = TypeResolver.resolveRawArgument(MyClass.class, myStringClass.getClass()); assert stringType == String.class;