可能重复:
为什么在运行时Java中没有删除所有类型信息?
Java的泛型是通过类型擦除实现的,所以我认为在运行时无法获得有关参数化类型的任何信息。但是,我在杰克逊图书馆找到了以下课程。
(为了这个例子,我稍微简化了这个类)
public abstract class TypeReference<T> {
final Type _type;
protected TypeReference() {
Type superClass = getClass().getGenericSuperclass();
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() { return _type; }
}
该类提供对其参数化类型的访问,如以下测试所示:
void testTypeReference() {
// notice that we're instantiating an anonymous subclass of TypeReference
TypeReference<CurrencyDto> tr = new TypeReference<CurrencyDto>() {};
assert tr.getType() == CurrencyDto.class
}
这个类说明了可以在运行时检索实际的类型参数(使用反射),这与Java泛型是通过类型擦除实现的概念是如何一致的?
具体 类型参数信息在编译时已知存储在类文件中。例如,如果您有一个返回方法的类 List<String>
(不 List<T>
!)该信息将在运行时可用。同样,如果你有一个班级:
public class Foo extends Bar<String> {
}
类型参数 String
是硬编码的 Foo
在编译时。该 TypeReference
class(和所有类似的结构,如 TypeLiteral
在Guice和 TypeToken
在Gson)通过要求你做一个来利用这个事实 匿名子类 它在你的代码中。执行此操作时,将生成具有该信息的实际类文件,就像使用该信息一样 Foo
上面的例子。
有关更多信息,请参阅Neal Gafter的博客文章 这里。
类型擦除更多是指您无法在运行时获取有关泛型类型实例的实际类型参数的信息(请注意 Foo
,。的子类 Bar<String>
,没有类型变量,也不是通用的)。例如,如果您创建泛型类型的实例 ArrayList<E>
:
List<String> foo = new ArrayList<String>();
没有类型信息存储在该对象中。所以当你把它传递给其他方法时:
public <T> T foo(List<T> list)
没有办法找出什么 T
是。
这非常简单:您无法从值INSTANCES获取通用信息,但您可以从TYPES(类)获取它,但有一些限制。具体来说,有3个地方可以获得通用类型信息(参见 http://www.cowtowncoder.com/blog/archives/2008/12/entry_126.html 详情);关于超类/接口声明(超类型的参数化),字段声明和方法(参数,返回类型)声明。
在TypeReference的情况下,发生的是你创建一个具有指定超类型的匿名类型;然后,这个信息将被传递,因为传递了匿名类型(类)。
我觉得这里没有真正的矛盾。
对于遗留代码,TypeReference在运行时将被视为原始TypeReference类型,但它仍然无法提供有关SomeType的信息。什么类型的擦除意味着您不能在运行时使用T of TypeReference 例如这里。但你仍然可以知道T被替换了什么..