# 虚拟机中的泛型类型信息

Type 是 Java 语言中所有类型的公共父接口。这就是最官方的解释。

Class 就是 Type 的一个直接实现类。Type 和 Class,以及 Type 的其它子接口(和实现类)组成了 Java 的类型体系。

# 1. Type 体系的历史

实际上,是先后 Class,而后有 Type 。也就是说,一开始并没有 Java 类型 体系 这样的概念。

是因为引入了泛型概念之后,为了将泛型概念引入 Java,并作出向后兼容,从而为 Class 『』 了一个 Type 祖先和其它“兄弟”, 从而完善了整个体系。

在早期的 Java (5.0 之前)中所有的类型都有一个 Class 对象,包括基本类型和自定义类型:

Student.class
Teacher.class
String.class
Integer.class
Double.class
Boolean.class
int.class
double.class
boolean.class
...

Class 对象中包含了当前类型的定义信息,它是 Java 反射的基础。通过一个类型的 Class 对象,你可以查询得到这个类型有哪些域,哪些方法,哪些构造函数等信息。

但是,在 JDK 5.0 引入泛型概念之后,Java 官方发现,新引入的泛型相关的一些类型,它们不适用上面我们所说的【所有的类型都有一个 Class 对象】这句话。

这些泛型相关的类型的那个对象 ,不能归类于是 Class 对象这个概念之下。它们的那个对象既和 Class 对象有相似的地方,又和 Class 对象有所区别。

对此,Java 官方抽取了它们和 Class 的相同点,提炼出 Type 概念,并补全了其它的类型:

  • ParameterizedType
  • TypeVariable
  • WildcardType
  • GenericArrayType

Type 和它的子接口、实现类(Class、ParameterizedType、TypeVariable、WildcardType、GenericArrayType)共同组成了 Java 的类型体系。

# 2. 各种 Type

以 HashMap 的类的定义为例:

public class HashMap<K, V> ... {
    ...
}

在这里出现了两种 Class 之外的 Type:

  • <K, V> 中的起到占位符作用的 K 和 V 的类型就是 TypeVariable
  • HashMap<K, V> 这个整体的类型就是 ParameterizedType

我们再以一个自定义的泛型类为例:

public class StringLinkedList<T> extends LinkedList<String> {
    private T[] array;
    ...
}

这里的私有属性 array 的类型 T[] 的类型就是 GenericArrayType

WildcardType 类型其实大家很早就见到过:Class<?> 中的这个 ? 的类型就是 WildcardType

当然,更复杂一点的泛型通配符可能会是这样:<? extends Number, ? extends Runnable>

# 3. 反射和Type

# 工具方法

为了更翻遍地检测 Type 的具体类型,我们可以准备一个如下的简单的方法:

private static String getTypeName(Type type) {
    if (type instanceof Class)
        return "Class";             // just like String
    else if (type instanceof TypeVariable)
        return "TypeVariable";      // just like T
    else if (type instanceof ParameterizedType)
        return "ParameterizedType"; // just like List<String>";
    else if (type instanceof GenericArrayType)
        return "GenericArrayType";  // just like T[]";
    else
        return "something wrong";   // 理论上不该如此
}

# 泛型方法和 Type

# getParameterTypes 方法

Method 的 getParameterTypes 方法用以获得方法参数的类型的类型。由于这是一个 1.5 的“老”方法,所以当它遇到泛型时,会执行泛型擦除。

假定有如下方法:

public static <T> void demo(T arg0, T[] arg1, String arg2) {
    ...
}

Method 的 getParameterTypes 方法的返回值是一个 Class 的数组,数组的三个成员分别是:

  • 第一个参数类型 Object, 类型为 Class;
  • 第二个参数类型 Object[], 类型为 Class;
  • 第三个参数类型 String,类型为 Class。

在这里,泛型 T 被擦除为 Object,泛型数组 T[] 被擦除为 Object[] 。

# getGenericParameterTypes 方法

Method 的 getGenericParameterTypes 方法的作用和上面的 getParameterTypes 方法类似,不过由于它是一个“新”方法,因此,它的返回结果中会保留泛型信息。

还是同样的上述方法:

public static <T> void demo(T arg0, T[] arg1, String arg2) {
    ...
}

getGenericParameterTypes 方法的返回值是 Type 的数组(而不是 Class 数组)

它的三个元素的分别是

  • 第一个参数类型 T ,类型为 TypeVariable
  • 第二个参数类型 T[], 类型为 GenericArrayType
  • 第三个参数类型 String, 类型为 Class

# getReturnType

Method 的 getReturnType 方法用以获取方法的返回值类型。如果涉及到泛型返回值,它会对泛型进行擦除。

假设有如下方法:

public static <T> T demo() {
    ...
}

getReturnType 方法返回的是返回值类型,也就是 Object 的类型:Class 。

在这里,泛型参数 T 被擦除为 Object 。

# getGenericReturnType

对于同样的方法,Method 的 getGenericReturnType 方法能识别出返回值类型的泛型信息。

它的返回是 T,其类型为 TypeVariable 。

# 泛型类和 Type

假定我们有一个自定义的泛型类:

public class StringLinkedList<T> extends LinkedList<String> {
    ...
}

# getTypeParameters

Class 的 getTypeParameters 可以返回泛型类的泛型参数。

StringLinkedList.class.getTypeParameters()[0]   // T

# getSuperclass

Class 的 getTypeParameters 可以返回泛型类的父类。这里会有泛型擦除。

StringLinkedList.class.getSuperclass()      // LinkedList

# getGenericSuperclass

Class 的 getGenericSuperclass 功能同 getSuperclass,不过它会保留父类的泛型信息。

StringLinkedList.class.getGenericSuperclass()   // LinkedList<String>

# ParameterizedType 的 getActualTypeArguments

Class 的 getGenericSuperclass 方法返回的是泛型父类,它的类型是 Type 。

实际上通过 instanceof 运算符,我们可以判断出泛型父类的实际信息是 ParameterizedType 类型。

而 ParameterizedType 类型有一个 getActualTypeArguments 方法,它能返回泛型父类的所使用的泛型参数。

 ParameterizedType superclass = (ParameterizedType) StringLinkedList.class.getGenericSuperclass();
for (Type cur : superclass.getActualTypeArguments()) {
    System.out.println(cur);    // 这个例子中只有一个:String
}