先上结论:上转型对象数组,不能添加子类类型以外的元素,编译可以通过,但是运行时会报错。
原文
在Java中,Object[]数组可以是任何数组的父类(因为任何一个数组都可以向上转型为它在定义时指定元素类型的父类的数组)。
考虑以下代码:
String[] strs = new String[10];
Object[] objs = strs;
obj[0] = new Date(...);
在上述代码中,我们将数组元素赋值为满足父类(Object)类型,但不同于原始类型(Pair)的对象,在编译时能够通过,而在运行时会抛出ArrayStoreException异常。
测试
当执行以下代码时:
String[] strs=new String[10];
Object[] objs=strs;
objs[0]=new Date();
确实报错:
Exception in thread "main" java.lang.ArrayStoreException: java.util.Date
at com.czl.Mould.main(Mould.java:12)
那看看上转型对象:
System.out.println("上转型对象");
String str=new String();
Object obj=str;
obj=new Date();
编译通过,运行正常。这个很简单,obj指向的地址值被改变了而已。
有意思了,看下面代码:
class fa{
fa(){
System.out.println("fa construction");
System.out.println("this"+this);
}
}
class son extends fa{
son(){
System.out.println("son construction");
}
}
class subson extends fa{
subson(){System.out.println("subson construction");}
}
执行下面代码:
fa[] fath = new son[10];
fath[0]=new subson();
结果报错:
Exception in thread "main" java.lang.ArrayStoreException: com.czl.subson
at com.czl.Mould.main(Mould.java:15)
fa construction
thiscom.czl.subson@49e6f7cb
subson construction
执行下面代码:
fa[] faths = new son[10];
faths = new subson[10];
faths[0] = new subson();
System.out.println("faths[0]"+faths[0]);
faths[1] = new son();
System.out.println("faths[1]"+faths[1]);
结果报错:
fa construction
thiscom.czl.subson@7e64eff0
subson construction
faths[0]com.czl.subson@7e64eff0
fa construction
thiscom.czl.son@20985fa2
son construction
Exception in thread "main" java.lang.ArrayStoreException: com.czl.son
at com.czl.Mould.main(Mould.java:21)
拓展
在泛型中,参数化类型的数组是不合法的。
考虑以下代码:
首先定义一个泛型类
public class Pair {
private T first;
private U second;
public Pair(T first, U second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public U getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(U newValue) {
second = newValue;
}
}
基于以上原因,假设Java允许我们通过以下语句声明并初始化一个泛型数组:
Pair[] pairs = new Pair[10];
那么在虚拟机进行类型擦除后,实际上pairs成为了Pair[]数组,我们可以将它向上转型为Object[]数组。这时我们若往其中添加Pair对象,便能通过编译时检查和运行时检查,而我们的本意是只想让这个数组存储Pair对象,这会产生难以定位的错误。因此,Java不允许我们通过以上的语句形式声明并初始化一个泛型数组。
可用如下语句声明并初始化一个泛型数组:
Pair[] pairs = (Pair[]) new Pair[10];