文章目录
  1. 1. 什么是泛型?
  2. 2. 泛型实现
  3. 3. 获取泛型的参数化类型
  4. 4. 代码示例,运行期通过反射获取泛型信息

这是《深入理解Java虚拟机第二版》的读书笔记。其中,通过反射获取泛型信息,是学习自这篇文章:http://tutorials.jenkov.com/java-reflection/generics.html

什么是泛型?

泛型是JDK 1.5的一项新增特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。使用泛型的场景:1,声明一个需要被参数化(parameterizable)的类/接口。2,使用一个参数化类。

泛型实现

Java语言中的泛型只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此,对于运行期的Java语言来说,ArrayList与Ar-rayList就是同一个类,所以泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型。

获取泛型的参数化类型
  • 由于Java泛型的引入,各种场景(虚拟机解析、反射等)下的方法调用都可能对原有的基础产生影响和新的需求,如在泛型类中如何获取传入的参数化类型等。因此,JCP组织对虚拟机规范做出了相应的修改,引入了诸如Signature、LocalVari-ableTypeTable等新的属性用于解决伴随泛型而来的参数类型的识别问题,Signature是其中最重要的一项属性,它的作用就是存储一个方法在字节码层面的特征签名,这个属性中保存的参数类型并不是原生类型,而是包括了参数化类型的信息。
  • 另外,从Signature属性的出现我们还可以得出结论,擦除法所谓的擦除,仅仅是对方法的Code属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,这也是我们能通过反射手段取得参数化类型的根本依据。
代码示例,运行期通过反射获取泛型信息
  • 方法返回值是泛型对象
    下面的代码,是当返回值是泛型对象时,在运行期获取泛型信息的一个例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyClass {
  protected List<String> stringList = ...;
  public List<String> getStringList(){
    return this.stringList;
  }
}

Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
    ParameterizedType type = (ParameterizedType) returnType;
    Type[] typeArguments = type.getActualTypeArguments();
    for(Type typeArgument : typeArguments){
        Class typeArgClass = (Class) typeArgument;
        System.out.println("typeArgClass = " + typeArgClass);
    }
}
  • 方法参数是泛型对象
    下面代码,是当参数是泛型对象时,获取泛型信息的例子.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyClass {
  protected List<String> stringList = ...;
  public void setStringList(List<String> list){
    this.stringList = list;
  }
}

method = Myclass.class.getMethod("setStringList", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
    if(genericParameterType instanceof ParameterizedType){
        ParameterizedType aType = (ParameterizedType) genericParameterType;
        Type[] parameterArgTypes = aType.getActualTypeArguments();
        for(Type parameterArgType : parameterArgTypes){
            Class parameterArgClass = (Class) parameterArgType;
            System.out.println("parameterArgClass = " + parameterArgClass);
        }
    }
}
  • 字段是泛型对象
    下面代码,是当字段的类型是泛型类时,获取泛型信息的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyClass {
  public List<String> stringList = ...;
}

Field field = MyClass.class.getField("stringList");
Type genericFieldType = field.getGenericType();
if(genericFieldType instanceof ParameterizedType){
    ParameterizedType aType = (ParameterizedType) genericFieldType;
    Type[] fieldArgTypes = aType.getActualTypeArguments();
    for(Type fieldArgType : fieldArgTypes){
        Class fieldArgClass = (Class) fieldArgType;
        System.out.println("fieldArgClass = " + fieldArgClass);
    }
}
文章目录
  1. 1. 什么是泛型?
  2. 2. 泛型实现
  3. 3. 获取泛型的参数化类型
  4. 4. 代码示例,运行期通过反射获取泛型信息