Java 泛型擦除详解

后端 潘老师 3个月前 (11-29) 70 ℃ (0) 扫码查看

本文主要讲解关于Java 泛型擦除相关内容,让我们来一起学习下吧!

1、什么是泛型擦除

泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉。

2、举例

  • 真相就是泛型在jvm都会被替换为Object
  • List list = new ArrayList< String>();左边编译时声明的静态类型,右边是运行时实现的实际类型
  • 那么list.add时则不会限制类型
public static void main(String[] args) {
    List list = new ArrayList();
    List listString = new ArrayList<String>();
    List listInteger = new ArrayList<Integer>();

    list.add(1);
    listString.add(123);
    listInteger.add("kentwang");

    System.out.println(list.size()+""+listString.size()+""+listInteger.size()+"");
    System.out.println(list.size()+""+listInteger.get(0));
}
  • 之所以get返回值时Object类型时因为在ArrayList 已经将泛型E擦除了,全都变为了Object,即使后边有类型转换,或者运行而不会报错。

3、会有啥问题

3.1、强制类型转换会有编译器无法检测的问题。

List listInteger = new ArrayList<Integer>();
listInteger.add("KENT");
System.out.println(""+(int)listInteger.get(0));
  • 这个不会报错,我申明是list,实现是ArrayList< Integer>,编译时静态类型是List。add可以加任何类型。运行时是ArrayList< Integer>实际类型,我强转为(Integer)应该的嘛,但是会出错

3.2、引用传递问题

  • 上面的问题中,我们已经说过了T将在后期被转义成Object,那我们对引用也进行一个转化,是否行得通呢?
//都会报错
List<String> listObject = new ArrayList<Object>();
List<Object> listObject = new ArrayList<String>();

假设说我们的第一种方案是正确的,那么其实就是将一堆Object数据存入,然后再由上面所说的强制转化一般,转化成String类型,听起来完全ok,因为在List中本来存储数据的方式就是Object。但其实是会出现ClassCastException的问题,因为Object是万物的基类,但是强转是为子类向父类准备的措施。

再来假设说我们的第二种方案是正确的,这个时候,根据上方的数据String存入,但是有什么意义存在呢?最后都还是要成Object的,你还不如就直接是Object

4、解决方案

  • 用泛型通配符
  • 强制类型转为的问题和引用传递问题,在编译期就给解决了
  • 看之前的《Java 泛型通配符详解》文章

5、要用Java泛型擦除的原因

  • java泛型是伪泛型,泛型擦除就是代码在编译阶段,与泛型相关的信息会被清除。
  • 泛型本质上是给编译器检查用的,并不改变运行时的类型。
  • java5新增泛型,如果用真泛型
    • 修改 JVM 源代码,让 JVM 能正确的的读取和校验泛型信息
    • 为了兼容老程序,需为原本不支持泛型的 API 平行添加一套泛型 API(主要是容器类型)。
    • java5之下的库A,要改代码,假设B项目升级到Java5,那么,A项目必要时要升级Java5,并且改代码。
    • 因为在 Java 中不支持高版本的 Java 编译生成的 class 文件在低版本的 JRE 上运行,如果尝试这么做,就会得到 UnsupportedClassVersionError 错误。如下图所示:
ArrayList<User> users = new ArrayList<>(); ArrayList<Dog> dogs = new ArrayList<>(); System.out.println(users.getClass() == dogs.getClass()); // 输出 true
  • 思来想去怎么让老版本不该,新版本改呢?我不增加API,在编译器检查时限制你,然后在编译器里擦除变为Object,再jvm里面新老版本就一样了。

以上就是关于Java 泛型擦除 相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/12000.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】