ArrayStoreException
之前一直以为数组的元素类型必须完全相同,不然运行时会报ArrayStoreException
,比如这样:
public class Test {
public static void main(String[] args){
Object[] objects = new String[10];
objects[0] = new Test();
}
}
但是看到规范上面的这一句:
If the type of the value being assigned is not assignment-compatible (§5.2) with the component type, an ArrayStoreException is thrown.
他既然这么说,数组的元素应该是可以不同类型。所以尝试了一下,有以下两种种情况:
- Array Creation Expressions
public class Test {
interface Noface {}
static class A implements Noface {}
static class B implements Noface {}
public static void main(String[] args){
Noface[] nofaces = new Noface[2];
nofaces[0] = new A();
nofaces[1] = new B();
}
}
不会有问题。相同的,创建一个父类的数组,用子类对象赋值给数组元素也不会有问题。
当然这很显然了
- Array Initializers
public class Test {
interface Noface {}
static class A implements Noface {}
static class B implements Noface {}
public static void main(String[] args){
Noface[] nofaces = {new A(), new B()};
System.out.println(nofaces.getClass());
}
}
输出:class [Ljava.lang.Object
这样也是没问题的,而且可以看到数组的类型是左侧的引用类型。反编译一下:
$ javap -c com.util.Test
Code:
0: iconst_2
1: anewarray #2 // class com/util/Test$Noface
创建一个大小为2的Noface
数组,这两段代码其实是等价的。
非基础类型数组实质上是一组引用,引用的类型完全相同,数组元素赋值也就是给对应位置的引用赋值,只要赋值的对象与数组元素类型相同或者是他的子类,就是assignment-compatible
。
类型
Java的数组是协变的,也就是说当类A是类B的父类的时候,A[]=new B[size]
是允许的,这与功能类似的集合类不一样,ArrayList<A> list = new ArrayList<B>()
就会报错。因为A[]是B[]的超类型,而ArrayList<A>不是ArrayList<B>的超类型。
If S and T are both reference types, then S[] >1 T[] iff S >1 T.
注:iff是if and only if的意思,并不是笔误。
而泛型的父子关系就比较复杂了
Given a generic type declaration C<F1,...,Fn> (n > 0), the direct supertypes of the parameterized type C<T1,...,Tn>, where Ti (1 ≤ i ≤ n) is a type, are all of the following:
D<U1 θ,...,Uk θ>, where D<U1,...,Uk> is a generic type which is a direct supertype of the generic type C<T1,...,Tn> and θ is the substitution [F1:=T1,...,Fn:=Tn].
C<S1,...,Sn>, where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
The type Object, if C<F1,...,Fn> is a generic interface type with no direct superinterfaces.
The raw type C.
简单举例解释一下:
-
List<A>
是ArrayList<A>
的超类型,因为List
是ArrayList
的父类,而且参数化类型完全相同 -
List
是List<A>
的超类型,因为List
是raw type
-
List<? extends A>
是List<A>
的超类型,因为? extends A
containsA
contain
A type argument T1 is said to contain another type argument T2, written T2 <= T1
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
在库函数中经常会见到这样的东西 <T extends Comparable<? super T>>
, 也是出于这样的原因。
heap pollution
- 我发现有些东西起个名字就会显得很高大上*
完
网友评论