为什么ArrayStoreException是RuntimeException?

ace*_*azz 3 java arrays exception-handling exception runtimeexception

假设我们有以下程序:

class Fruit {}

class Apple extends Fruit {} 

class Jonathan extends Apple {} 

class Orange extends Fruit {} 

public class Main { 
    public static void main(String[] args) { 
        Fruit[] fruit = new Apple[10];

        try { 
            fruit[0] = new Fruit(); // ArrayStoreException 
            fruit[0] = new Orange(); // ArrayStoreException 
        } catch(Exception e) { System.out.println(e); } 
    } 
}
Run Code Online (Sandbox Code Playgroud)

基于Java文档:

抛出以指示已尝试将错误类型的对象存储到对象数组中.

我在这里读到了

创建数组时,它会记住它要存储的数据类型.

如果数组记住它包含的数据类型,则意味着它知道它包含的数据类型.但是我发布的代码片段是正确编译的,所以在编译时,数组显然不知道包含什么类型.

我的问题是:

  1. 为什么ArrayStoreException只在运行时抛出?

  2. 编译器缺少哪些信息来实现该分配是不可能的?

  3. 有没有这样的代码是正确的,所以没有ArrayStoreException抛出?

Jon*_*eet 5

如果数组记住它包含的数据类型,则意味着它知道它包含的数据类型.

在执行时,是......就像在执行时一样,对象的类型是已知的:

Object x = "foo";
// The compiler won't let you call x.length() here, because the variable
// x is of type Object, not String.
Run Code Online (Sandbox Code Playgroud)

另一种方法是使非常多的数组赋值隐式抛出一个已检查的异常.那太糟糕了 - 类似于NullPointerException检查.

编译器缺少哪些信息来实现该分配是不可能的?

正如你所见,数组是协变的.当编译器看到的转让成Fruit[]Apple,它不能知道什么实际数组的类型将是.如果是,Fruit[]或者Apple[],那没关系.如果不是这样的Orange[]话.该信息仅在执行时出现 - 再次,就像编译器不知道表达式是否绝对不为空.

是否存在此类代码正确的情况,因此不会抛出ArrayStoreException?

好吧,如果你有一个具有最终类的编译时元素的数组,那么你就不能有任何较低的方差.例如:

public void foo(String[] array) {
    array[0] = "x";
}
Run Code Online (Sandbox Code Playgroud)

这可能会因为array存在null或空而引发异常,但它永远不会抛出异常ArrayStoreException,因为它String是最终的.实施永远不会是一个SubclassOfString[].