List list = new ArrayList<Integer>();//为什么能添加任何类型
List<String> list = new ArrayList<>();//只能添加String类型
List list = new ArrayList<Integer>();//为什么能添加任何类型
List<String> list = new ArrayList<>();//只能添加String类型
要区分数组和泛型容器,那么就需要先理解以下三个概念:协变性(covariance)、逆变性(contravariance)和无关性(invariant)。
若类A是类B的子类,则记作A≦B。设有变换f(),则有以下定律:
在Java语言中,数组具有协变性,而泛型具有无关性,示例代码如下所示:
Object[] array = new Integer[1];
//这里ide会有红色下划线,表示编译错误。
ArrayList<Object> list = new ArrayList<Integer>();
以上这两行代码,数组正常编译通过,而泛型抛出了编译期错误,应用之前提出的概念对代码进行分析,可知以下推论:
数组的变换可以表达为f(A)=A[],通过之前的示例
可以得出以下推论:
f(String) = String[] 以及 f(Object) = Object[]
通过代码验证,String[]≦Object[]是成立的,由此可见,数组具有协变性。ArrayList泛型的变换可以表达为f(A)=ArrayList
得出以下推论:
f(String) = ArrayList<String> 以及 f(Object) = ArrayList<Object>
最终得出结论,数组具备协变性,而泛型具备无关性。
所以,为了让泛型具备协变性和逆变性,Java引入了有界泛型的概念。
除了协变性的不同,数组还是具象化的,而泛型不是。
什么是具象化(也可以称之为具体化,物化)?在《Java语言规范》里,明确地规定了具象化类型的定义:
完全在运行时可用的类型被称为具象化类型(refiable type),会做这种区分是因为有些类型会在编译过程中被擦除,并不是所有的类型都在运行时可用。它包括:
无论是在编译时还是运行时,数组都能确切地知道自己所属的类型。但是泛型在编译时会丢失部分类型信息,在运行时,它又会被当作Object处理。
Java的泛型最后都被当作上界 `(? extend Type )`
处理了。
换言之,数组必须清楚地知道自己内部元素的类型,并且会一直保存这个类型信息,在添加元素的时候,该信息会被用于做类型检查,而泛型的类型是不确定的。所以,在编译器层面就杜绝了这个问题的发生。这在《Java语言规范》里有明确地说明:
If the element type of an array were not reifiable,
the virtual machinecould not perform the store check described
in the preceding paragraph.This is why
creation of arrays of non-reifiable types is forbidden.
Onemay declare variables of array types whose element
type is not reifiable,but any attempt to assign them a value will
give rise to an uncheckedwarning.
如果数组的元素类型不是具象化的,那么虚拟机将无法应用在前面章节里描述过的存储检
查。这就是为什么创建(实例化)非具象化的数组是不允许
的。你可以定义(声明)一个元素类型是非具象化的数组类
型,但任何试图给它分配一个值的操
作,都会产生一个unchecked warning。存储检查:
这里涉及Array的基本原理,可以自行参阅《Java语言规范》
泛型具有无关系。
3 回答2.6k 阅读✓ 已解决
3 回答4.1k 阅读✓ 已解决
8 回答3.8k 阅读
4 回答2.8k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
3 回答2.7k 阅读✓ 已解决
3 回答2.6k 阅读✓ 已解决
泛型只是在编译期检查类型,在运行时泛型已经不存在了,这个写法是在实例化的时候声明了泛型,但是赋值给list的时候泛型丢弃了,因为list的声明类型是 List,List本身不带泛型相当于List<Object>或者 List<?> 所以可以添加任何类型
这个写法相当于
List<String> list = new ArrayList<String>();
,只是java8时加入的一个简化写法而已,效果是一样的修正:是java7加入的语法糖,类型推断