【发布时间】:2013-04-12 02:09:35
【问题描述】:
这是否会导致运行时异常而不是 Java 中的编译时错误?
Object[] objects = new Object[10];
String[] strings = (String[])objects;
【问题讨论】:
这是否会导致运行时异常而不是 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[] 创建的数组。
【讨论】:
String[] → Object[] → String[] 和String[] → Object[] → Integer[]?这是一个引导性的问题。答案当然是the JLS does not require the compiler to perform such checks.
因为 这是语言规范定义的编译时行为。 简短的版本是 Object[] 可以转换为 String[] 而不会产生编译时错误,因为Object 可以转换为 String 而不会产生编译时错误。
长答案只是我引用了 JLS。来自the Java Language Specification § 5.5.1. Reference Type Casting:
给定一个编译时引用类型 S(源)和一个编译时引用类型 T(目标),如果由于以下规则而没有发生编译时错误,则存在从 S 到 T 的强制转换。
...
如果S是数组类型SC[],即SC类型的组件数组:
...
- 如果 T 是数组类型 TC
[],即 TC 类型的组件数组,则除非满足以下条件之一,否则会发生编译时错误:
- TC 和 SC 是相同的原始类型。
- TC 和 SC 是引用类型,类型 SC 可以转换为 TC。
根据同一节中关于转换的前面的规则,Objects 可以转换为 Strings:
如果 S 是类类型:
- 如果 T 是类类型,那么 |S| <:>
以防万一您想知道:
根据§5.5.1. 中的规则,如果没有发生编译时错误,则引用类型的表达式可能会转换为另一个引用类型
注意the JLS uses |T| to denote the erasure of type T 和S :> T indicates that the supertype relation holds between S and T. 因此“|S| <: or s t>
【讨论】:
StringBuilder sb = new StringBuilder(); Object o = sb; Integer i = (Integer) o; 你能解释一下为什么吗?这似乎表明上述情况不是一个特殊情况......但我确定我误解了一些东西。
Object 在编译器的混乱中。如果您真的想了解,请花时间深入了解 JLS §5.5.1。和 5.5.2.
null 的变量时,Java 会抛出 NullPointerException?因为 JLS 说它必须这样做。”归根结底,关于 Java 为什么会执行 JLS 指定的事情的问题应该被解释为为什么 JLS 是以这种特定方式编写的问题,否则它是没有意义的。
强制转换是 Java 出于灵活性目的而提供的一个根本不安全的特性。如果您的编译器设置正确调整,该代码会生成“未经检查”的警告。
【讨论】: