3

简单地:

public static class MyClass<T> {
    // 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<T> mArrayList = new ArrayList<T>();
    // the problem of getting the generic type parameter is still present.
}

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>();
    getParamType( myObject );
}

private static final <T> void getParamType(final MyClass<T> _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()- 因为在这个简单的案例中不涉及继承。
  • 而且我也无法将其投射到ParameterizedType

.

System.out.println((ParameterizedType) _myObject.getClass());
// Compile Error: Cannot cast from Class<capture#11-of ? extends TreeTest2.MyClass> to ParameterizedType

System.out.println((ParameterizedType) _myObject.getClass().getGenericSuperclass());
// Runtime Exception: java.lang.ClassCastException

根据@Thomas 的指南,我找到了一种解决方法来获取class java.lang.Integer.

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

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

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

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

它完美打印class java.lang.Integer

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

这种方法基于TypeReference 类的思想。但我真的不知道如何使用它。我试过了class MyClass<T> extends TypeReference<T>。但我仍然必须创建子类MyClass<T>才能拥有TypeReference.getType()prints class java.lang.Integer

请提供帮助,并感谢您的任何意见,因为最好的方法还没有出现。


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

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
}

MyClass并且getParamType()不变。)

4

4 回答 4

3

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

解决方法称为超类型令牌。SO上也有一些关于这个的主题(比如这个那个)。

于 2013-08-20T14:29:57.837 回答
2

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

没有泛型的程序如下所示:

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()?
}
于 2013-08-20T21:53:20.823 回答
1

Java 有一个被称为类型擦除的误导性功能,它专门阻止您这样做。

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

相反,您可以手动接受Class<T>.

于 2013-08-20T14:24:24.007 回答
0

要了解T你需要通过继承 MyClass 在类型定义中捕获它的价值:

class MyStringClass extends MyClass<String> {}

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

MyClass<String> myStringClass = new MyClass<String>{}();

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

Class<?> stringType = TypeResolver.resolveRawArgument(MyClass.class, myStringClass.getClass());
assert stringType == String.class;
于 2013-10-26T02:39:02.613 回答