新闻资讯

新闻资讯 媒体报道

Java泛型那些事[干货]

编辑:016     时间:2021-11-18

泛型的类型检测

通过前一篇的类型擦除,我们已经了解到对于List<String> 、List<Integer>这些泛型类,在编译后是原始的类型,即List即内部的原始类型为Object。可以看看下面这个例子

List<String>的实例和List<Integer>都是基于编译后的同一个字节码文件,而在ArrayList的字节码文件中,它内部的原始数据类型就是Object类型。前一篇已经给出很多示例的证明,这里不再叙述。

public class TestGeneric { public static void main(String[] args) throws Exception { List<String> list1=new ArrayList<String>(); List<Integer> list2=new ArrayList<Integer>(); System.out.println(list1.getClass()==list2.getClass()); } }

从这个示例,笔者要引入一个关于泛型对象引用的问题。

  • 第一种:叫做原始类型的编码风格。
  • 第二种:在编码设计阶段,叫做类型参数化的编码风格,即泛型风格
  • 第三种:在编码设计阶段,原始类型兼容的编码风格。
public class TestGeneric { public static void main(String[] args) throws Exception { //第一种写法:jdk1.5之前的写法  List list=new ArrayList(); //第二种写法:jdk1.5之后的写法  List<Integer> list2=new ArrayList<Integer>(); //第三种:兼容的写法  List<Integer> list3=new ArrayList<>(); //第四种:这种写法不建议  List list4=new ArrayList<Integer>(); } }

它们对于JVM来说,最终会转换为第一种编码风格List list=new ArrayList()。因为类型擦除后,其他list的内部都持有的数据类型是java.lang.Object。对于第一种和第四种,因为它们无法提供泛型编程的类型检测

第2种和第3种在主流的JDK中都是推荐的写法,先看看下面这两种编程风格

public class TestGeneric { public static void main(String[] args) throws Exception { List<Integer> list3=new ArrayList(); list4.add(324); Integer val=list3.get(0); } }

首先,new ArrayList()它告知JVM为其申请一段内存空间,这片内存空间可以存储任意类型的对象,而List<Integer> list这段声明就告知JVM编译时类型检测以及类型擦除后的代码上下文添加必要的类型强转代码,这就意味着

  • 通过引用该声明(即 List<Integer>)的变量list3调用add()方法,添加Integer类型的数据,在ArrayList对象内部就能自动完成了向上类型转换操作,即Integer类型转换为Object类型。
  • 通过引用该声明(即 List<Integer>)的变量list3调用get()方法,Java编译器已经再编译时加入了自动完成了向下类型强转(即关于Object到Integer的类型补偿),即如下图所示

那么理解了Java编辑器对List<Integer> list3=newArrayList();这条语句的操作之后,现在来查看一个示例的对比,这段程序是可以编译通过的,因为第47行的list3.get(0)仅仅是告知Java编辑器从ArrayList内部以Object类型的理解方式获取该位置的数据,而没有做类型补偿。

而再来看这段代码,这段代码别说编译了,根本就无法通过Java编译器的类型检测。

首先第45行使用的原始的List声明,而不是List<Integer>声明,这里就告知Java编译器这仅仅是一个不需要内置类型强制的且原始数据类型是Object的ArrayList。

然后第47行的val变量却使用了Integer类型声明,就告知Java编译器以Integer类型的方式从ArrayList的内存块的第一个位置读取该数据。这与之前list3引用的List原始声明是矛盾的。因此编译器就会抱怨类型转换错误:“nai nai 的兄,指鹿为马有意思吗?”

小结:

通过上面的例子,不论泛型与否,类型检查就是针对类型声明的引用,当一个引用变量被使用时,Java编译器就对这个引用调用的泛型方法进行类型检测,而和真正引用的对象没任何关系。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表

相关推荐