我正在阅读有效Java的项目28,作者写在其中
数组和仿制药之间的第二个主要区别是数组 被校正[JLS,4.7]。这意味着阵列知道并执行他们的 运行时元素类型。
但是为什么在运行时?例如,考虑两个类,其中a是b
的父母public static void main(String[] args) {
A[] array = new B[10];
array[0] = new A();
}
此代码抛出一个arraystoreException。对我来说,似乎已经由编译器确定了错误。那么,为什么编译器让它通过。是因为JLS不希望编译器成为那么聪明(慢)?
JLS 10.5 对于一个类型为a []的数组,其中a是参考类型, 运行时间检查对数组组件的分配 确保分配的值可分配给组件。
现在我的理解是
- 在编译时(以及运行时)数组变量上面的示例具有type a []
- 编译器的职责是确保仅将[]的某些子类型分配给数组变量。
- 阵列的组件(array [0])也是如此,编译器将仅检查分配的值是一个或某些子类型。
为什么当将A()分配给数组[0]时,编译器不考虑实际数组对象(B [10])。是因为编译器没有可用的信息吗?
对我来说,似乎已经由编译器确定了错误。
好吧;编译器无法确定运行时array
的实际类型。
让我们做一个琐碎的例子
array = myRandomFunction()>0 ? new A[10] : new B[10];
然后,array
的实际类型可以是A[]
或B[]
,并且编译器无济于事。
如果您考虑一下;这类似于NullPointerException
发生的事情:编译器不会抱怨以下内容(即使是否总是在运行时投掷)
Object a=null;
a.toString();
可以由您发布的代码中的编译器检测到错误,但在一般情况下却不能检测到错误。
由于协方差,可以将B[]
分配给第一行中的A[]
变量。如果将该数组传递给在第二行中进行分配的方法,则编译器将无法检测到数组的原始类型。
因此,这两条线在编译时均有效。