深入理解Java虚拟机之Java泛型--读书笔记
更新日期:
这是《深入理解Java虚拟机第二版》的读书笔记。其中,通过反射获取泛型信息,是学习自这篇文章:http://tutorials.jenkov.com/java-reflection/generics.html
什么是泛型?
泛型是JDK 1.5的一项新增特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。使用泛型的场景:1,声明一个需要被参数化(parameterizable)的类/接口。2,使用一个参数化类。
泛型实现
Java语言中的泛型只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此,对于运行期的Java语言来说,ArrayList
获取泛型的参数化类型
- 由于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); } } |