1.java可以声明泛型数组吗?
我们都知道在java中声明一个普通数组,但是你知道如何声明一个泛型数组吗?
先来看一个简单的例子,Animals是 Cat的父类,思考下Animals[]和Cat[] ,以及 List
Cat[] cat = new Cat[10];
// 编译通过
Animals[] animals = cat;
// 编译通过 运行报错
animals[0]=new Dog();
List<Cat> catList = new ArrayList();
// 编译报错
List<Animals>=catList;
这里我们会发现一个奇怪的问题 ,Cat[] 类型的值可以赋值给 Animals[]类型,而 List
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
这里就涉及到一个关键点,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