首页 > 编程语言 >你真的了解java的泛型吗?

你真的了解java的泛型吗?

时间:2022-08-25 17:45:59浏览次数:56  
标签:java ArrayList List Cat 泛型 new 真的

1.java可以声明泛型数组吗?

​ 我们都知道在java中声明一个普通数组,但是你知道如何声明一个泛型数组吗?

​ 先来看一个简单的例子,Animals是 Cat的父类,思考下Animals[]和Cat[] ,以及 List和List是什么关系?

 Cat[] cat = new Cat[10];
 // 编译通过
 Animals[] animals = cat;
 // 编译通过 运行报错
 animals[0]=new Dog();
 
 List<Cat> catList = new ArrayList();
 // 编译报错
 List<Animals>=catList;

​ 这里我们会发现一个奇怪的问题 ,Cat[] 类型的值可以赋值给 Animals[]类型,而 List类型赋值给 List在编译阶段就报错了,这是其中有什么不同吗?在解释为什么java无法声明泛型数组前,我们先看一下下面的例子

Cat[] cat = new Cat[10];

List<Cat> catList = new ArrayList();

System.out.println(cat.getClass());

System.out.println(catList.getClass());

运行结果

class [LCat;
class java.util.ArrayList

​ 我们可以我发现,数组在运行时可以获取自身类型,而List在运行时只能知道自己是一个List,而无法获取参数类型。这说明java的泛型其实是泛型擦除,也就是伪泛型。

​ 这里就涉及到一个关键点,java的数组是协变的,而List是不变的。协变的意思就是 任意类A和B,若A是B的父类,则A[]也是B[]的父类。如果给数组加上泛型,就会无法满足协变原则,因为无法在运行时知道数组的类型。所以java是无法声明泛型数组的。

2.java的泛型为什么要通过泛型擦除来实现?

​ java有一大特性,向后兼容,就是老版本的java文件可以运行在新版本的jvm上。java一开始并没有泛型的,在jdk1.5以前,程序中会出现大量以下的代码:

List list = new ArrayList();

一般在没有泛型的语言上支持泛型,有两种方式,以集合为例:

  • 全新设计一个新的集合框架,优点就是不需要考虑兼容老代码,缺点是需要适应新的语法,更严重可能无法改造老的业务代码
  • 在老的集合框架上进行改造,添加一些特性,兼容老代码的前提下,支持泛型

java选择了第二种,主要由以下两种原因:

  • 在jdk1.5以前已经有大量非泛型代码存在了,如果不兼容它们,会让使用者抗拒升级。
  • jdk.1.1 升级到 jdk1.2中 Vector 到 ArrayList ,HashTable 到 HashMap ,引起大量使用者不满

所以java为了填补自己以前的坑,选择了一种比较别扭的方式实现泛型,就是类型擦除。

那么,为什么使用类型擦除可以实现上面所说的新老代码兼容问题呢?

我们看下面两行代码

List list = new ArrayList();
List<String> list2 = new ArrayList();

编译后的字节码内容如下:

L0
 LINENUMBER 13 L0
 NEW java/util/ArrayList
 DUP
 INVOKESPECIAL java/util/ArrayList.<init> ()V
 ASTORE 1
L1
 LINENUMBER 14 L1
 NEW java/util/ArrayList
 DUP
 INVOKESPECIAL java/util/ArrayList.<init> ()V
 ASTORE 2

​ 我们发现两种创建集合的方式编译后的字节码是完全一样的,这也就说明低版本编译的class文件在高版本上运行不会出现问题,那么既然是类型擦除,java是怎么保证泛型的特性呢,比如类型检查、类型自动转换?

我们来看看java是怎么做的

List<String> list = new ArrayList();
list.get(0);

点进get方法,我们发现java是通过类型强制转换来保证相关泛型的特性

@SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }




public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
}

标签:java,ArrayList,List,Cat,泛型,new,真的
From: https://www.cnblogs.com/wlstudy09/p/16625064.html

相关文章

  • java操作selenium浏览器自动化操作
    seleniumgithubselenium官网各类型浏览器webDriver驱动下载chrome浏览器webDriver驱动下载,注意要与电脑上实际安装的浏览器版本相对应原理说明:java代码直接通过sele......
  • Caused by: java.lang.UnsupportedClassVersionError: com/hfplm/handler/HFEBOMation
    Causedby:java.lang.UnsupportedClassVersionError:com/hfplm/handler/HFEBOMationHandlerhasbeencompiledbyamorerecentversionoftheJavaRuntime(classf......
  • Java 连接 MySQL
    让Java和MySQL连接起来-囧雪诺-博客园 https://www.cnblogs.com/jonsnow/p/6246131.htmlJava连接MySQL需要驱动包,可以下载菜鸟教程提供的 jar包:http://stati......
  • 【Java】LambdaStream
    JavaLambdaStreamFactoryimportjava.util.*;importjava.util.stream.*;publicclassLambdaStream{publicstatic<T>Stream<T>of(Spliterator<T>split......
  • Java生成带logo的二维码,并将二维码添加到图片中
    1.pom.xml<!--生成二维码--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-extra</artifactId><version>5.4.3</version></dependency><d......
  • java的String.format中的百分号
    System.out.println(String.format("百分比%.2f%",(float)80/90));错误信息:Exceptioninthread"main"java.util.UnknownFormatConversionException:Conversion=......
  • JavaScript中改变鼠标指针样式的方法
    JavaScript中改变鼠标指针样式的方法    在js中我们可以通过style对象的cursor属性来设置鼠标指针的样式,例varbody=document.querySelector("body") body.style......
  • JAVA---06
    第六天1.instanceof和类型转化instanceof:用于比较两个对象是否有继承关系类型转化:低可以直接转高Person //父类Student//子类   //子类转化为父类......
  • 第一个JAVA小程序
    HelloWorld随便新建一个文件,修改后缀名称为“.java”需要注意的地方:注意大小写,注意各个类的英文单词拼写不能写错在编写程序时尽可能使用英文书写(哪怕输出......
  • python 3 用pyexecjs 执行 javascript 代码
    #运行js代码e=execjs.eval('a=newArray(1,2,3)')#execjs.eval()获取js环境,直接执行js代码,适用于简单的运算适用于从前端读取js代码然后运行(前后......