这是否有特殊原因导致运行时异常而不是 Java 中的编译时错误?
Object[] objects = new Object[10];
String[] strings = (String[])objects;
由于这种情况,必须在运行时进行检查:
public class Test {
public static void main(String[] args){
String[] stringsBase = {"aaa", "bbb", "ccc"};
Object[] objects = stringsBase;
String[] strings = (String[])objects;
System.out.println(strings[1]);
}
}
这是一个有效的工作程序。在不进行流分析的情况下,编译器不知道对象是否引用了作为 Object[] 创建的数组,或者在本例中作为 String[] 创建的数组。
因为这是语言规范定义的编译时行为。简短的版本是Object[]
可以将 an 强制转换为 aString[]
而不会生成编译时错误,因为Object
可以将 an 强制转换为 aString
而不会生成编译时错误。
长答案只是我引用了 JLS。来自Java 语言规范 § 5.5.1。参考类型转换:
给定一个编译时引用类型 S(源)和一个编译时引用类型 T(目标),如果由于以下规则而没有发生编译时错误,则存在从 S 到 T 的强制转换。
...
如果 S 是数组类型 SC[]
,即 SC 类型的组件数组:
...
- 如果 T 是 TC 类型的数组
[]
,即 TC 类型的组件数组,则除非满足以下条件之一,否则会发生编译时错误:
- TC 和 SC 是相同的原始类型。
- TC 和 SC 是引用类型,类型 SC 可以转换为 TC。
根据关于强制转换的同一部分中的一条前面的规则,Object
s 可以进行强制转换为String
s:
如果 S 是类类型:
- 如果 T 是类类型,那么 |S| <: |T|,或 |T| <: |S|。否则,会发生编译时错误。
以防万一你想知道:
如果根据§5.5.1中的规则没有发生编译时错误,则引用类型的表达式可能会转换为另一个引用类型。
请注意,JLS 用于|T|
表示类型的擦除,T
并且S :> T 表示 S 和 T 之间存在超类型关系。因此“|S| <: |T| 或 |T| <: |S|” 可以理解为“S 的擦除是 T 的子类型、相同类型或超类型”。
强制转换是 Java 出于灵活性目的而提供的一个根本不安全的特性。如果您的编译器设置正确调整,该代码会生成“未经检查”的警告。