java泛型运行时类型

时间:2014-02-11 01:30:03

标签: java generics reflection runtime

post I found by Ian Robertson有一个很好的实用工具方法,用于确定Java类类型参数的运行时类。它比快速版本快了几步:

ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
Class<?> c = (Class<?>) pt.getActualTypeArguments()[0]

这两种方法的工作方式类似于从抽象参数化父级(class Foo<T> extends Bar<T>)继承的参数化子级的魅力,或者参数化抽象类(new Foo<Bar>() {})的匿名实例,并使用具体类型进行实例化。


我失败的地方是尝试对通过类型参数实例化的其他对象执行相同的操作。相关的类对象是:

public class Foo {/* code omitted for brevity */}

public class MyFoo extends Foo {/* code omitted for brevity */}

public abstract class AbstractLoader<T extends Foo> {/* code omitted for brevity */}

public abstract class AbstractReader<T extends Foo> {/* code omitted for brevity */}

public class MyReader<T extends Foo> extends AbstractReader<T> {/* code omitted for brevity */}

public class Loader<T extends Foo> extends AbstractLoader<T> {
    /* code omitted for brevity */

    public MyReader<T> getReader() {
        // Parameterized type "T" doesn't seem to carry through here
        return new MyReader<T>();
    }
}

示例代码:

static void main(String... s) {
    Loader<MyFoo> loader = new Loader<>(); // new Loader<MyFoo>() for Java < 1.7
    MyReader<MyFoo> = loader.getReader();

    ParameterizedType pt = (ParameterizedType)loader.getClass().getGenericSuperclass();
    System.out.println("LoaderType = " + pt.getActualTypeArguments()[0]);
    // Prints: LoaderType = MyFoo

    pt = (ParameterizedType)reader.getClass().getGenericSuperclass();
    System.out.println("ReaderType = " + pt.getActualTypeArguments()[0]);
    // Prints: ReaderType = T
}

直觉告诉我这个&#34;应该&#34;以某种方式可能,但我似乎无法找到正确的答案。 OTOH,这可能是&#34;无法做到的另一个例子&#34;由于类型擦除。

2 个答案:

答案 0 :(得分:1)

你完全误解了什么。运行时new Loader();new Loader<Integer>();new Loader<Object>();等之间存在 NO DIFFERENCE 。不可能区分它们。现在就把这个想法从脑海中解脱出来。

如果我们创建一个类,那么关于该类的声明中的类型(包括泛型),包括超类,方法类型,字段类型等,都存储在类文件中。可以在运行时检索此信息。

因此,当您拥有new Foo<Bar>() {}时,会创建某个类(匿名类)的实例,该类扩展具有特定类型参数的泛型类型。它类似于:

class SomeAnonymousClass extends Foo<Bar> {
}
new SomeAnonymousClass()

Foo<Bar>在编译时被硬编码为此类的超类,这在运行时是可检索的。

但是你的代码没有做这种事。您没有创建Loader的任何子类。

答案 1 :(得分:0)

您无法找到对象的类型参数 - 它会在运行时被删除。

如果可以,Loader loader0Loader<MyFoo> loader1Loader<MyBar> loader2会给出不同的结果。这种差异必须以某种方式在运行时表示:直接在对象中,或通过引用不同的类。第一个变体需要为每个实例添加额外的内存,并被认为是不合适的。第二个需要在运行时创建类,因为类Loader本身不能包含参数化类Loader的所有可能变体 - 它们在编译时是未知的。