专业的JAVA编程教程与资源

网站首页 > java教程 正文

你了解泛型被擦除以后又是如何获取到实际类型呢?

temp10 2025-08-06 22:56:07 java教程 10 ℃ 0 评论

一、什么是泛型

百科定义:JDK在1.5版本中引入的新特性,在定义类型的时候可以是一个“参数类型”,对应的有泛型类,泛型接口及泛型方法。

你了解泛型被擦除以后又是如何获取到实际类型呢?

Java中的泛型是伪泛型,这个我们后面会讲到

示例

public class Generator<T> //泛型类

public interface Generator<T> //泛型接口

public <T> void generator(T t) //泛型方法


二、为什么要引入泛型

核心就一点:类型安全;如果没有泛型,那就必须使用强制类型转换,这样是极不安全的,在运行时很容易出现类型转换的异常,如果使用泛型,在编译阶段就可以避免出现该类问题。

三、什么是泛型擦除

“泛型擦除”这个词很有意思,也是我们今天讨论的重点。顾名思义,就是JVM在编译阶段将泛型给去除掉,实际运行的时候是没有泛型概念的,可能读者会比较好奇,为什么要这么干,之前不是鼓励定义泛型吗?其实这个“擦除”不是程序员的行为,而是编译器的行为:

编译器在将java文件编译成class文件的过程中会将我们定义的泛型擦除

那么接下来的问题来了,编译器为什么要这么干?关于这个问题,其实在开始介绍泛型定义的时候就提到关键的一点

Java中的泛型是“伪泛型”,而不是“真泛型”

“为什么要泛型擦除”这个问题实际上就变成了“为什么Java要实现伪泛型”,核心原因我觉的就一点吧:兼容性,为了兼容1.5之前的Java应用,让低版本的应用可以在高版本的JVM上运行,具体的本文就不做详细的赘述了,读者如果有兴趣可以百科下。

四、泛型擦除后运行时如何获取具体的类型

我们在开发业务代码的过程中,经常会遇到如下情况,请求一个外部接口,该接口返回json,是一个字符串,我们再将其转换成自己定义的类型,比如

[{"name":"张三","age":30},{"name":"李四","age":40}]

上述报文我们将其转换成List<Person>,其中的Person就是泛型,那么问题来了,编译阶段泛型不是被擦除了么,为什么还能转换成我们所定义的泛型呢?

//代码示例,内部封装的json解析工具是Gson
Response<List<Person>> response = 
  JsonHelper.parseObject(result, new TypeToken<Response<List<Person>>>() {
                    });

上面代码中的List<Person>这都是泛型,Gson是如何反解析出原始类型的呢,通过查看TypeToken的源代码发现关键点有两个:

1、new TypeToken(){} 创建匿名类

2、其内部的resolveType方法(细节不在这里展示了,有兴趣的读者可以去看看源码)

resolveType方法最终是通过反射还是能拿到泛型的实际类型,明明在编译的时候擦除了,这不是前后矛盾,至此引出本文的关键点:

泛型擦除是有范围的,针对类内部定义的泛型是不会被擦除的

很多框架都是利用了这个特性来获取泛型的

五、总结

  1. Java中的泛型是伪泛型,编译时会被擦除
  2. 官方搞伪泛型是折中方案,考虑兼容性
  3. 泛型擦除是有范围的,类内部定义的泛型不会擦除

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表