首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么ArrayStoreException是RuntimeException?

为什么ArrayStoreException是RuntimeException?
EN

Stack Overflow用户
提问于 2016-07-15 08:14:58
回答 4查看 606关注 0票数 3

假设我们有以下程序:

代码语言:javascript
复制
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); } 
    } 
}

基于Java文档

引发,以指示已尝试将错误类型的对象存储到对象数组中。

我读过这里

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

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

我的问题是:

  1. 为什么只在运行时抛出ArrayStoreException
  2. 编译器缺少哪些信息来意识到分配是不可能的?
  3. 在任何情况下,这些代码都是正确的,因此不会抛出ArrayStoreException吗?
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-07-15 09:18:23

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

数组“只记得”它在运行时实际包含的类型。

首先,将数组声明为果树数组。

然后创建数组,在本例中是Apple的数组。

创建是在运行时进行的,但编译器的设计仅用于验证数组是否仅被指定为它声明为的类型的对象。在运行时,有很多事情可以发生。

考虑以下代码:

代码语言:javascript
复制
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];
        boolean alt = (Math.random() < 0.5);

        try { 
            fruit[0] = fruitFactory(alt); 
        } catch(Exception e) { System.out.println(e); } 
    } 

    private static Fruit fruitFactory(boolean apple) {
        if (apple) {
            return new Apple();
        } else {
            return new Orange();
        }
    } 
}

该代码与您的代码相同,只是fruitFactory方法为水果分配了一个值。编译器无法判断布尔alt是true还是false

编译器缺少哪些信息来意识到分配是不可能的?

如前所述,编译器无法判断分配是否可行。

在任何情况下,这些代码都是正确的,因此不会抛出ArrayStoreException吗?

是的,在以上代码中的50 %的情况下。您必须验证分配的对象是否与数组相同,或者捕获异常。

票数 2
EN

Stack Overflow用户

发布于 2016-07-15 08:20:14

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

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

代码语言:javascript
复制
Object x = "foo";
// The compiler won't let you call x.length() here, because the variable
// x is of type Object, not String.

另一种方法是进行非常多的数组赋值,隐式抛出一个检查异常。这将是可怕的-类似于让NullPointerException检查。

编译器缺少哪些信息来意识到分配是不可能的?

正如您所看到的,数组是协变量的。当编译器看到一个赋值到一个Fruit[]Apple中时,它无法知道该数组的实际类型。如果是Fruit[]Apple[],那就好了。如果是Orange[],那就不是。该信息仅在执行时才出现,就像编译器不知道表达式是否为null一样。

在任何情况下,这些代码都是正确的,因此不会抛出ArrayStoreException吗?

如果您有一个数组,其中包含最后一个类的编译时元素,那么就不可能有任何较低的方差。例如:

代码语言:javascript
复制
public void foo(String[] array) {
    array[0] = "x";
}

这可能会引发由于arraynull或空而引发的异常,但是它不会抛出ArrayStoreException,因为String是最终的。实现不可能是SubclassOfString[]

票数 5
EN

Stack Overflow用户

发布于 2016-07-15 08:21:12

出于与ClassCastException相同的原因,这是一个运行时异常。并不总是能够在编译时判断该类型是否符合您的预期。

考虑一下这个例子:

代码语言:javascript
复制
void method1() {
    Fruit[] fruits = getFruits();
    fruits[0] = new Orange();
}

Fruit[] getFruits() {
    if (someCondition) {
        return new Apple[5];
    } else {
        return new Orange[5];
    }
}

编译器无法知道当您调用someConditiongetFruits()将处于什么状态。因此出现了运行时异常。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38391161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档