描述
理解
题目中的这段程序在编译器正常,运行时异常。错误出现在 b[1] = Integer.valueOf(42);
这一行代码, a
赋值给 b
,a
和 b
指向同一对象 new String[2]
,而 String[]
的实现是不支持 set integer
操作。
这行引发运行时异常。从实现角度来说,Java的数组是协变的:也就说Java的类型系统认为子类数组可以被赋值给父类数组。而这种赋值和对象的多态类似,它并不会实际改变数组元素的实际类型,于是乎在上述的例子中尽管b表面上是Object[]类型,但是运行时它的实际类型是String[],内部元素也只能添加字符串(因为Java的数组不同与泛型,数组是存在运行时类型检查的),于是就引发了这种现象:编译期编译通过(因为表面的类型检查认为没有什么问题),运行时抛出异常(把事实上的Integer对象存进了String数组)。
作者:陆萌萌
链接:https://www.zhihu.com/question/371957442/answer/1017620831
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如果想要编译时报错,我们可以用 List
代替 Array
:
public class TestJava {
public static void f() {
String[] a = new String[2];
Object[] b = a;
a[0] = "hi";
b[1] = Integer.valueOf(42); // 此处运行时异常
System.out.println(a);
System.out.println(b);
}
public static void o() {
List<String> a = new ArrayList<>(2);
List<Object> b = a; // 此处类型检查时会报错
a.set(0, "hi");
b.set(1, Integer.valueOf(42));
}
public static void main(String[] args) {
f();
}
}
参考:
一道 Java 面试题:https://www.yinwang.org/blog-cn/2020/02/13/java-type-system
知乎讨论:https://www.zhihu.com/question/371957442