你了解泛型被擦除以后又是如何获取到实际类型呢?
一、什么是泛型
百科定义:JDK在1.5版本中引入的新特性,在定义类型的时候可以是一个“参数类型”,对应的有泛型类,泛型接口及泛型方法。
Java中的泛型是伪泛型,这个我们后面会讲到
示例
public class Generator
//泛型类 public interface Generator
//泛型接口 public
void generator(T t) //泛型方法
二、为什么要引入泛型
核心就一点:类型安全;如果没有泛型,那就必须使用强制类型转换,这样是极不安全的,在运行时很容易出现类型转换的异常,如果使用泛型,在编译阶段就可以避免出现该类问题。
三、什么是泛型擦除
“泛型擦除”这个词很有意思,也是我们今天讨论的重点。顾名思义,就是JVM在编译阶段将泛型给去除掉,实际运行的时候是没有泛型概念的,可能读者会比较好奇,为什么要这么干,之前不是鼓励定义泛型吗?其实这个“擦除”不是程序员的行为,而是编译器的行为:
编译器在将java文件编译成class文件的过程中会将我们定义的泛型擦除
那么接下来的问题来了,编译器为什么要这么干?关于这个问题,其实在开始介绍泛型定义的时候就提到关键的一点
Java中的泛型是“伪泛型”,而不是“真泛型”
“为什么要泛型擦除”这个问题实际上就变成了“为什么Java要实现伪泛型”,核心原因我觉的就一点吧:兼容性,为了兼容1.5之前的Java应用,让低版本的应用可以在高版本的JVM上运行,具体的本文就不做详细的赘述了,读者如果有兴趣可以百科下。
四、泛型擦除后运行时如何获取具体的类型
我们在开发业务代码的过程中,经常会遇到如下情况,请求一个外部接口,该接口返回json,是一个字符串,我们再将其转换成自己定义的类型,比如
[{"name":"张三","age":30},{"name":"李四","age":40}]
上述报文我们将其转换成List
//代码示例,内部封装的json解析工具是Gson
Response<List> response =
JsonHelper.parseObject(result, new TypeToken<Response<List>>() {
});
上面代码中的List
1、new TypeToken(){} 创建匿名类
2、其内部的resolveType方法(细节不在这里展示了,有兴趣的读者可以去看看源码)
resolveType方法最终是通过反射还是能拿到泛型的实际类型,明明在编译的时候擦除了,这不是前后矛盾,至此引出本文的关键点:
泛型擦除是有范围的,针对类内部定义的泛型是不会被擦除的
很多框架都是利用了这个特性来获取泛型的
五、总结
- Java中的泛型是伪泛型,编译时会被擦除
- 官方搞伪泛型是折中方案,考虑兼容性
- 泛型擦除是有范围的,类内部定义的泛型不会擦除