假设我们有以下程序:

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 documentation:

抛出以表示已尝试存储错误的内容
将对象类型转换为对象数组。

我读过here

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

如果数组记住了它包含的数据类型,则意味着它知道它包含的数据类型。但是我发布的代码段已正确编译,因此在编译时,数组显然不知道所包含的类型。

我的问题是:
  • 为什么只在运行时抛出ArrayStoreException
  • 编译器缺少哪些信息,以致于无法进行分配?
  • 在任何情况下此类代码都是正确的,因此不会抛出ArrayStoreException吗?
  • 最佳答案

    创建数组时,它会记住它意味着什么类型的数据
    商店。

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

    首先声明数组,在这种情况下,声明为Fruit数组。

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

    创建是在运行时期间进行的,但是编译器仅设计用于验证仅向数组分配了声明为其类型的对象。在运行期间可能发生很多事情。

    考虑以下代码:

    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方法为fruit [0]分配了一个值。编译器无法判断布尔alt是true还是false

    编译器缺少哪些信息才能意识到这一点
    分配是不可能的吗?

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

    有没有这样的代码是正确的,所以没有
    引发ArrayStoreException吗?

    是的,在上面的代码中有50%的情况。您要么必须验证分配的对象与数组相同,要么捕获异常。

    09-28 10:27