本文讨论 Java 范型的一些容易混淆的地方。用一句话总结就是:类型擦除是一个过度简化的说法。

Java 范型使用了类型擦除的方案。原因是需要兼容老代码。类型擦除是一个过度简化的说法,其精确含义是指 List<T>List 在运行时的类型是同一个,即类对象是一个。但是,对于另外大多数情况,Java 提供在运行时获取范型参数类型的方法。

考虑这样一个类:

public class ParameterizedGenericClass extends List<String> {
  private List<Integer> parameterizedGenericField;
}

ParameterizedGenericClass 继承自参数化了的范型类型,并且拥有一个参数化了的范型成员变量。Java 提供了在运行时获取这两个范型参数的 API:

第一个方法是类上面的方法,第二个方法是字段上的方法。运行时这些类型信息都保存在 ParameterizedGenericClass 的类对象上。这也是为什么 List<T> 的类型参数信息被擦除了而 ParameterizedGenericClass 的没有——因为所有的 List<T> 在运行时的类对象是同一个,无法保存多份参数化信息;而 ParameterizedGenericClass 只需要关心它自己的信息。

使用这两个方法来完善的处理各种情况(多层继承等),需要做进一步的工作。在框架或者库代码中,往往会使用这种技巧。比如 JSON 解析库 Jackson、Gson 都使用了这种技术以得到更简洁的 API。

comments powered by Disqus