3

这是否有特殊原因导致运行时异常而不是 Java 中的编译时错误?

Object[] objects = new Object[10];
String[] strings = (String[])objects;
4

3 回答 3

5

由于这种情况,必须在运行时进行检查:

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[] 创建的数组。

于 2013-04-12T02:25:00.713 回答
2

因为这是语言规范定义的编译时行为。简短的版本是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。

根据关于强制转换的同一部分中的一条前面的规则,Objects 可以进行强制转换为Strings:

如果 S 是类类型:

  • 如果 T 是类类型,那么 |S| <: |T|,或 |T| <: |S|。否则,会发生编译时错误。

以防万一你想知道:

如果根据§5.5.1中的规则没有发生编译时错误,则引用类型的表达式可能会转换为另一个引用类型。


请注意,JLS 用于|T|表示类型的擦除,T并且S :> T 表示 S 和 T 之间存在超类型关系。因此“|S| <: |T| 或 |T| <: |S|” 可以理解为“S 的擦除是 T 的子类型、相同类型或超类型”。

于 2013-04-12T02:19:28.360 回答
0

强制转换是 Java 出于灵活性目的而提供的一个根本不安全的特性。如果您的编译器设置正确调整,该代码会生成“未经检查”的警告。

于 2013-04-12T02:16:59.693 回答