泛型与反射的使用总结之反射篇

你的名字 2021-06-10 20:42 396阅读 0赞
  1. 前一篇对泛型进行了一番总结,本篇就来说说与泛型有关的反射。
  2. 我在泛型篇中说到了泛型在 JVM 中是会被擦除的,不过擦除的类还是“残留”了一些泛型的痕迹。比如 Person<T> 类,虽然擦除掉了泛型 <T> ,但是通过反射机制是可以获得这些信息的,不光如此, Person 类里面定义的泛型方法都可以通过反射获得。让我们用代码来验证一下。
  3. 在用代码验证之前,大象会对 Person 类稍微改造一下,增加一个泛型变量 K 以及一个泛型方法,其它的都保持不变。
  4. public class Person<T, K extends Comparable<? super T> & Serializable>
  5. extends SuperPerson<String> implements Handle<Date> \{
  6. ......
  7. public static <T extends Comparable<? super T>> T max(List<? extends T> list)\{
  8. Iterator<? extends T> it = list.iterator();
  9. T result = it.next();
  10. while (it.hasNext())\{
  11. T t = it.next();
  12. if (t.compareTo(result) > 0)
  13. result = t;
  14. \}
  15. return result;
  16. \}
  17. ......
  18. \}
  19. 下面可以开始写代码了吗?别急,大象还想先把代码中用到的几个跟反射有关的 API 接口说明一下,这都是 JDK5.0 中为泛型新增的,然后还用到了一个 JDK6.0 提供的 Modifier ,它是一个枚举类型 ,可以表示 类、方法或字段的修饰符。
  20. **Type**
  21. 它是所有类型的公共接口。包括原始类型、参数化类型、数组类型、类型变量和基本类型。 ParameterizedType, TypeVariable, WildcardType,GenericArrayType 这四个接口都是它的子接口。
  22. **GenericDeclaration**
  23. 这个接口 Class Method Constructor 都有实现,我们就是要用这个接口的 getTypeParameters 方法,它返回一个 TypeVariable\[\] 数组,这个数组里面就是我们定义的类型变量 T K ,顺序与我们声明时一样。如果用循环语句将数组打印出来,你会发现只会输出 T K ,这可不是我们想要的结果,那么想要获得预期的结果怎么办呢?请继续往下看。
  24. **TypeVariable**
  25. 它表示类型变量。比如 T ,比如 K extends Comparable<? super T> & Serializable ,这个接口里面有个 getBounds () 方法,它用来获得类型变量上限的 Type 数组,如果没有定义上限,则默认设定上限为 Object ,请注意 TypeVariable 是接口,实际得到的是 TypeVariableImpl 实现类,下面几个接口都一样。
  26. TK来说明,T没有定义任何上限,所以它就有一个默认上限java.lang.Object,实际跟踪代码的时候你会发现Tbounds属性为空,只有在调用了getBounds()方法后,才会有一个Type\[1\]数组\[class java.lang.Object\]。而对于K来说,调用了getBounds方法后,得到的数组是\[java.lang.Comparable<? super T>, interface java.io.Serializable\],它们的类型却是不一样的,第1个是ParameterizedType,而第二个是Class
  27. **ParameterizedType**
  28. ParameterizedType表示参数化类型,就是上面说的java.lang.Comparable<? super T>,再比如List<T>,List<String>,这些都叫参数化类型。得到Comparable<? super T>之后,再调用getRawType()与getActualTypeArguments()两个方法,就可以得到声明此参数化类型的类(java.lang.Comparable)和实际的类型参数数组(\[? super T\]),而这个? super T又是一个WildcardType类型。
  29. **WildcardType**
  30. 它用来描述通配符表达式,上面返回的 ? super T 正好是这个类型。然后调用 getUpperBounds() 上限和 getLowerBounds() 下限这两个方法,获得类型变量 ? 的限定类型 ( 上下限 ) ,对于本例的通配符 (?) ,它的上限为 java.lang.Object ,下限为 T

通过上面几个接口的分析,可以将 Person 类的泛型参数都解析出来,那么 Person 的超类以及实现的接口该怎么处理呢? Class 类里面同样在 1.5 版本加入了 getGenericSuperclass() 与 getGenericInterfaces() 两个方法,用于返回带参数化类型的超类与接口。
至此,通过上面这些接口和方法我们已经可以把 class Person 后面的代码都解析出来了,类里面的方法与解析类的泛型化参数类似,就不再赘述了。下图就是通过反射将定义的 Person 类打印出来的结果。
reflect.jpg
本文主要是想通过反射机制来验证在 JVM 虚拟机中获得泛型的一些知识。一般实际使用的时候多数是通过反射获取超类的泛型,或者通过反射调用方法,读取 / 设置属性值等等这些功能,最下面有示例源码的下载。
反射虽然很有用处,但也不能滥用。首先用了反射就没办法在编译时进行类型检查,而且反射的代码比较复杂不容易阅读,不过好在现在有很多已经封装好的反射工具类,帮我们做了不少这方面的工作。最后也是最重要的一点是因为,使用反射会有一定的性能损耗,就是说会比直接调用方法要慢,至于慢多少,这个不好说,但肯定会慢,因此除非有必要,大象建议在一般情况下首先考虑用接口来代替反射。
以上这些都是本篇关于泛型相关的反射介绍,算是一个入门知识吧,有什么不对的,或不完善的地方,还请各位指出来,谢谢!
源码下载: 泛型与反射
本文为菠萝大象原创,如要转载请注明出处。 http://www.blogjava.net/bolo

发表评论

表情:
评论列表 (有 0 条评论,396人围观)

还没有评论,来说两句吧...

相关阅读

    相关 反射

    反射是Java语言中很重要的一个组成部分,所以就此话题讨论的资源可谓数之不尽,日常开发也会经常使用到关于反射的Reflection API。Java5.0 Tiger出现以后,