在通用上下文中使用getActualTypeArguments

And*_*aam 7 java generics reflection class

还有其他相关问题,例如6624113,3403909,4516891但我的问题是更简单,更具体.

我想在运行时知道我的类参数化了什么类型 - 我想要一个类型参数类型的Class对象.由于类型擦除,表达式T.class不起作用,并且没有像typeof(T)C#中那样的函数来获取它.

但是,通过ParameterizedType和相关类可以获得一些"超级反射" ,这几乎可以解决所有问题.

import java.lang.reflect.ParameterizedType;

public class MyClass<T> {
    public static void main( String[] args ) {
        new MyClass<Integer>().printTypeParam();
    }

    public void printTypeParam() {
        class DummyT extends MyClass<T> {}
        class DummyString extends MyClass<String> {}

        ParameterizedType ptT =
            ((ParameterizedType) DummyT.class.getGenericSuperclass() );

        ParameterizedType ptString =
            ((ParameterizedType) DummyString.class.getGenericSuperclass() );

        System.out.println( "DummyT: " + ptT + " " + ptT.getActualTypeArguments()[0] );
        System.out.println( "DummyString: " + ptString + " " + ptString.getActualTypeArguments()[0] );

    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行上面的内容时,我看到了这个输出:

DummyT: MyClass<T> T
DummyString: MyClass<java.lang.String> class java.lang.String
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这适用于在编译时在包含调用的代码行中已知类型参数getGenericSuperClass,但是在该调用本身处理泛型的情况下,它只是打印类型参数的名称.

有什么办法可以让第一行打印java.lang.Integer而不是T

Mar*_*ers 4

你不能,简单明了。 Integer没有具体化,而是被彻底抹去了。如果您不相信我,请使用Integer和 分别编译该文件一次Long。这两个二进制类文件将完全相同。

类型擦除是一个你无法回避的残酷现实。我建议你重新思考为什么需要它,而不是走上引入黑客的道路来试图避免它。

有用的 AngelikaLanger 仿制药常见问题解答主题:

  • 我实际上做了你的建议,你会毫不惊讶地听到你是对的:创建了 2 个文件: MyClass$1DummyString.class MyClass$1DummyT.class MyClass.class 如果我更改第 5 行的类型,它们是二进制相同的为长整型而不是整数。 (2认同)