OCA Java SE 8备考疑问:数组引用与类型转换代码报错解析
关于Java数组协变与
ArrayStoreException的解惑 让我一步步拆解你这段代码,帮你搞懂Error 2的本质:
先理清代码中每个变量的「编译类型」和「实际指向的对象类型」
这是理解问题的核心:
String[] strings = { "stringValue" };:创建了一个**实际类型为String[]**的数组对象,strings引用的编译类型也是String[],完全匹配。Object[] objects = strings;:这里用到了Java数组的「协变性」——子类数组可以赋值给父类数组类型的引用。注意:objects的编译类型是Object[],但它实际指向的对象还是原来的String[]数组,并没有把String[]转换成Object[]对象,只是换了个“父类视角”来引用它。String[] againStrings = (String[]) objects;:这是合法的向下转型,因为objects实际指向的就是String[],所以编译和运行都不会报错,againStrings重新用String[]的视角引用了同一个数组。
为什么Error 1编译不通过,Error 2编译通过但运行报错?
- Error 1:
againStrings的编译类型是String[],编译器明确知道这个数组只能存储String或其子类对象,StringBuilder和String没有继承关系,所以直接在编译阶段就阻止了这种操作,很容易理解。 - Error 2:
- 编译阶段:
objects的编译类型是Object[],编译器认为Object[]可以存储任何Object的子类(StringBuilder确实是Object的子类),所以编译通过。 - 运行阶段:Java数组是「具体化类型」,运行时会保留数组本身的实际类型信息。当你尝试往数组里存元素时,JVM会检查这个元素的类型是否符合数组的实际类型(也就是
String[])。StringBuilder不是String的子类,不符合要求,所以会抛出ArrayStoreException。
- 编译阶段:
用通俗的例子类比
就像你把一只猫装在标着「动物」的笼子里(Object[] objects = strings),笼子的标签是「动物笼」(编译类型Object[]),但里面实际装的还是猫(实际类型String[])。你不能把狗(StringBuilder)放进这个笼子里,因为笼子本质是用来装猫的,哪怕标签写的是动物笼。
内容的提问来源于stack exchange,提问作者TPA
相关产品推荐
相关产品推荐

