简体   繁体   English

java泛型运行时类型

[英]java generics runtime type

A post I found by Ian Robertson has a great utility method for determining the runtime class for a Java class type parameter. 我在Ian Robertson找到的帖子中有一个很好的实用方法,用于确定Java类类型参数的运行时类。 It goes a few steps beyond the quick version: 它比快速版本快了几步:

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

Either method works like a charm for parameterized children inheriting from an abstract parameterized parent ( class Foo<T> extends Bar<T> ), or an anonymous instance of a parameterized abstract class ( new Foo<Bar>() {} ), and instantiated with a concrete type. 这两种方法的作用类似于从抽象参数化父class Foo<T> extends Bar<T>继承的参数化子class Foo<T> extends Bar<T>class Foo<T> extends Bar<T> ),或者参数化抽象类的匿名实例( new Foo<Bar>() {} ),以及用具体类型实例化。


Where I fail is in trying to do the same for some other object instantiated via type parameter. 我失败的地方是尝试对通过类型参数实例化的其他对象执行相同的操作。 Relevant class objects are: 相关的类对象是:

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

Sample Code: 示例代码:

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
}

Intuition tells me this "should" be possible somehow, but I can't seem to discover the right answer. 直觉告诉我这种“应该”是可能的,但我似乎无法找到正确的答案。 OTOH, this may be another example of "can't do that" due to type erasure. OTOH,这可能是由于类型擦除而“无法做到”的另一个例子。

You are completely misunderstanding something. 你完全误解了什么。 There is NO DIFFERENCE between new Loader(); new Loader();之间没有差异 new Loader(); , new Loader<Integer>(); new Loader<Integer>(); , and new Loader<Object>(); ,和new Loader<Object>(); , etc. at runtime. 等等。在运行时。 It is impossible to tell them apart. 不可能区分它们。 Get that notion out of your head right now. 现在就把这个想法从头脑中解脱出来。

If we create a class, then the types (including generics) in the declarations about that class, including superclass, method types, field types, etc. are stored in the class file. 如果我们创建一个类,那么关于该类的声明中的类型(包括泛型),包括超类,方法类型,字段类型等,都存储在类文件中。 This information can be retrieved at runtime. 可以在运行时检索此信息。

So when you have new Foo<Bar>() {} , that creates an instance of a certain class (an anonymous class) which extends a generic type with a specific type parameter. 因此,当您有new Foo<Bar>() {}时,会创建某个类(匿名类)的实例,该类扩展具有特定类型参数的泛型类型。 It's similar to: 它类似于:

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

The fact that Foo<Bar> is hard-coded at compile-time as the superclass of this class, this is retrievable at runtime. 事实上, Foo<Bar>在编译时被硬编码为此类的类,这在运行时是可检索的。

But your code is doing nothing of this sort. 但是你的代码没有做这种事。 You did not make any subclasses of Loader . 你没有创建Loader任何子类。

You cannot find type parameter for an object - it is erased at run time. 您找不到对象的类型参数 - 它在运行时被删除。

If you could, then Loader loader0 , Loader<MyFoo> loader1 , and Loader<MyBar> loader2 would give different results. 如果可以,那么Loader loader0Loader<MyFoo> loader1Loader<MyBar> loader2会给出不同的结果。 This difference has to be represented in runtime somehow: either in objects directly, or by referencing different classes. 这种差异必须以某种方式在运行时表示:直接在对象中,或通过引用不同的类。 The first variant require additional memory for each instance and was considered unappropriate. 第一个变体需要为每个实例添加额外的内存,并被认为是不合适的。 The second requires creating classes at runtime, as class Loader itself cannot contain all possible variants of parameterized class Loader - they are unknown at compile time. 第二个需要在运行时创建类,因为类Loader本身不能包含参数化类Loader的所有可能变体 - 它们在编译时是未知的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM