《Java 核心技术 卷一》 泛型类型章节中“仍会导致一个类型错误” 是什么类型错误 ?
这个 “仍会导致一个类型错误” 是什么类型错误 ?
回答:
private static class Pair<T> {
public T t ;
public Pair(T t) {
this.t = t;
}
}
public static void main(String[] args) {
Pair<String> pairs[]=new Pair[10];
Object objPairs[]=pairs;
//这里报错是因为声明类型虽然为Object,但是实际的数组类型已经确定了为Pair,所以在赋值时就会报错了
//java.lang.ArrayStoreException: java.lang.String
// objPairs[0]="123";
//这里并不会报错,因为能通过类型检查: 泛型因为被擦除,最后检查的都是Pair<Object>
objPairs[0]=new Pair<Integer>(1);
//但是如果我在通过pairs数组去拿就会出错了
//java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Pair<String> pair = pairs[0];
//8.6.3的小节标题就是结论: 不能创建参数化类型的数组,因为泛型擦除了,我个人理解是创建了也没啥用,在编译器检测不出来错误。
}
回答:
要区分数组和泛型容器,那么就需要先理解以下三个概念:协变性(covariance)、逆变性(contravariance)和无关性(invariant)。
若类A是类B的子类,则记作A≦B。设有变换f(),则有以下定律:
- 当A≦B时,有f(A)≦f(B),则称变换f()具有协变性。
- 当A≦B时,有f(B)≦f(A),则称变换f()具有逆变性。
- 如果以上两者皆不成立,那么称变换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),会做这种区分是因为有些类型会在编译过程中被擦除,并不是所有的类型都在运行时可用。它包括:
- 非泛型类声明,接口类型声明。
- 所有泛型参数类型为无界通配符(仅用‘?’修饰)的泛型参数类。
- 原始类型。
- 基本数据类型。
- 其元素类型为具象化类型的数组。
- 嵌套类(内部类、匿名内部类等,例如java.util.HashMap.Entry),并且嵌套过程中的每一个类都是具象化的。
无论是在编译时还是运行时,数组都能确切地知道自己所属的类型。但是泛型在编译时会丢失部分类型信息,在运行时,它又会被当作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语言规范》
泛型具有无关系。
.......
以上是 《Java 核心技术 卷一》 泛型类型章节中“仍会导致一个类型错误” 是什么类型错误 ? 的全部内容, 来源链接: utcz.com/p/944968.html