当前位置: 首页 > article >正文

【Java基础面试题034】Java泛型擦除是什么?

回答重点

泛型擦除指的是Java编译器在编译时将所有泛型信息删除的过程,以确保与Java1.4及之前的版本保持兼容

泛型参数在运行时会被替换为其上界(通常是Object),这样一来在运行时无法获取泛型的实际类型。

作用:泛型擦除确保了Java代码的向下兼容性,即可以与旧版本的Java代码兼容,为了让使用泛型的代码在不同版本的Java运行时环境中都可以正常工作。又由于泛型类型信息在编译时期被擦除了,因此运行时无法获取泛型信息,这样就不能创建泛型类型的数组或对泛型类型使用instanceof检查

示例:

public <T> void printList(List<T> list) {
   for (T element : list) {
       System.out.println(element);
   }
}

编译后的代码类似于:

public void printList(List list) {
   for (Object element : list) {
       System.out.println(element);
   }
}

类型T会被擦除成Object

扩展知识

为什么Java泛型的实现是类型擦除?

回答重点提到了主要原因是为了向下兼容,即兼容Java5之前编译的class文件。

例如Java1.2上正在跑的代码,可以在Java1.5上的JRE上运行

也是因为需要向下兼容,才使得Java实现的是伪泛型

我从现有的实现倒推伪泛型的设计可能思路(个人瞎掰的,做个参考即可)

是这样的:

  1. 这Java5以前的版本在线上已经有很多应用在跑了,如果我的Java5不能兼容,没人用啊
  2. 泛型毕竟是加一个约束,以前的代码没有这个约束啊,该如何兼容?
  3. 有了,要不我在编译器上动手动脚,在编译的时候识别和约束泛型,然后编译过了就把泛型的信息擦除了。这样运行的时候就没有约束了,跟之前的版本就没什么区别了。

参考网上的解释:

这说明,写Java的也是程序员,也是要发版有上线需求的

为什么运行期通过反射可以获得类型?

public class GenericTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");
        String s = list.get(0);
    }
}

看字节码 

从反编译看生成的字节码文件能看到,new的List没有保存泛型,所以是被擦除了

下面有一步checkcast强转为String,可是Java代码中不需要写强转呢?

因为编译器隐形的帮我们插入了强转的代码所以不需要我们写

再看标题:既然擦除了类型,为什么运行期还能通过反射获取类型?

答案就藏在class文件中

看下面代码:

获取泛型类型

public class GenericTest {
    public List<String> list;
    public static void main(String[] args) throws Exception{
        Field field = GenericTest.class.getField("list");
        Type type = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
        System.out.println(type);
    }
}

javap -v,可以看到字节码里记录了泛型类型信息,所以编译器虽然擦除了泛型类型,也记录了泛型信息,自然能通过反射获取

由于静态记录在了字节码中,所以局部变量这种存在栈中的泛型类型,通过反射就无法获取

只有三种情况可以通过反射获取泛型类型:

  • 成员变量的泛型
  • 方法入参的泛型
  • 方法返回值的泛型
  • 类的泛型


http://www.kler.cn/a/448842.html

相关文章:

  • 前端开发 之 12个鼠标交互特效上【附完整源码】
  • 安卓从Excel文件导入数据到SQLite数据库的实现
  • vue iframe进行父子页面通信并切换URL
  • SpringBoot+Vue3实现阿里云视频点播 实现教育网站 在上面上传对应的视频,用户开会员以后才能查看视频
  • Qt5HttpServer : Qt官方的HTTP服务器
  • 圣诞快乐(h5 css js(圣诞树))
  • 基于大语言模型的多代理下一代制造系统能灵活动态管理制造资源的高效调度方法
  • 一种统计torch内部计算过程算子输入输出信息的方法
  • (css)鼠标移入或点击改变背景图片
  • windows 下使用WLS2 编译aosp Android14并刷机到pixle 5a
  • 鱼跃医疗获评2024年国家级“绿色工厂”,以绿色制造树立行业标杆
  • 《 火星人 》
  • 基础爬虫案例实战
  • 【Threejs】从零开始(六)--GUI调试开发3D效果
  • C05S13-MySQL数据库备份与恢复
  • 运用软件开发的三层结构创建图书馆查书
  • STM32-KEIL5中相关设置
  • vue 文本域 展示的内容格式要和填写时保持一致
  • 「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
  • ctf中遇到exec和shell_exec的回显问题
  • 基于SpringBoot的“家具销售电商平台”的设计与实现(源码+数据库+文档+PPT)
  • Stream流的使用
  • 【Python 】循环
  • matplotlib中文字体 graphviz中文字体
  • 基于WCF(C#)+SQL SERVER设计与实现的在线评测系统
  • 前端获取excel表格数据并在浏览器展示