[英]java generics runtime type
我在Ian Robertson找到的帖子中有一个很好的实用方法,用于确定Java类类型参数的运行时类。 它比快速版本快了几步:
ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
Class<?> c = (Class<?>) pt.getActualTypeArguments()[0]
这两种方法的作用类似于从抽象参数化父class Foo<T> extends Bar<T>
继承的参数化子class Foo<T> extends Bar<T>
( 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
}
直觉告诉我这种“应该”是可能的,但我似乎无法找到正确的答案。 OTOH,这可能是由于类型擦除而“无法做到”的另一个例子。
你完全误解了什么。 new Loader();
之间没有差异 new Loader();
, new Loader<Integer>();
,和new Loader<Object>();
等等。在运行时。 不可能区分它们。 现在就把这个想法从头脑中解脱出来。
如果我们创建一个类,那么关于该类的声明中的类型(包括泛型),包括超类,方法类型,字段类型等,都存储在类文件中。 可以在运行时检索此信息。
因此,当您有new Foo<Bar>() {}
时,会创建某个类(匿名类)的实例,该类扩展具有特定类型参数的泛型类型。 它类似于:
class SomeAnonymousClass extends Foo<Bar> {
}
new SomeAnonymousClass()
事实上, Foo<Bar>
在编译时被硬编码为此类的超类,这在运行时是可检索的。
但是你的代码没有做这种事。 你没有创建Loader
任何子类。
您找不到对象的类型参数 - 它在运行时被删除。
如果可以,那么Loader loader0
, Loader<MyFoo> loader1
和Loader<MyBar> loader2
会给出不同的结果。 这种差异必须以某种方式在运行时表示:直接在对象中,或通过引用不同的类。 第一个变体需要为每个实例添加额外的内存,并被认为是不合适的。 第二个需要在运行时创建类,因为类Loader本身不能包含参数化类Loader的所有可能变体 - 它们在编译时是未知的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.