Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么ArrayStoreException是RuntimeException?_Java_Arrays_Exception_Exception Handling_Runtimeexception - Fatal编程技术网

Java 为什么ArrayStoreException是RuntimeException?

Java 为什么ArrayStoreException是RuntimeException?,java,arrays,exception,exception-handling,runtimeexception,Java,Arrays,Exception,Exception Handling,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 {

假设我们有以下程序:

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); } 
    } 
}
根据:

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

我读过

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

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

我的问题是:

  • 为什么只在运行时抛出
    ArrayStoreException

  • 编译器缺少哪些信息来认识到该赋值是不可能的

  • 是否存在这样的情况:此类代码是正确的,因此不会引发
    ArrayStoreException
  • 如果数组记住它包含的数据类型,则表示它知道它包含的数据类型

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

    Object x = "foo";
    // The compiler won't let you call x.length() here, because the variable
    // x is of type Object, not String.
    
    另一种方法是使很多数组赋值隐式抛出一个选中的异常。这将是可怕的-类似于检查
    NullPointerException

    编译器缺少哪些信息来认识到该赋值是不可能的

    正如您所看到的,数组是协变的。当编译器看到一个赋值到
    苹果的
    果实[]
    中时,它无法知道该数组的实际类型。如果是
    水果[]
    苹果[]
    ,那就好了。如果它是
    Orange[]
    则不是。这些信息只在执行时出现——同样,就像编译器不知道表达式是否绝对不是null一样

    是否存在这样的情况:这样的代码是正确的,因此不会引发ArrayStoreException

    如果有一个数组,它的编译时元素是final类,那么方差就不能再低了。例如:

    public void foo(String[] array) {
        array[0] = "x";
    }
    

    由于
    array
    null
    或为空,它可能会引发异常,但它永远不会引发
    ArrayStoreException
    ,因为
    String
    是最终的。该实现永远不能是
    子类字符串[]

    它是运行时异常,原因与
    ClassCastException
    相同。并不总是能够在编译时判断类型是否是您期望的类型

    考虑这个例子:

    void method1() {
        Fruit[] fruits = getFruits();
        fruits[0] = new Orange();
    }
    
    Fruit[] getFruits() {
        if (someCondition) {
            return new Apple[5];
        } else {
            return new Orange[5];
        }
    }
    

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

    在您的例子中,apple和orange被隐式地浇铸到水果中,因为它们是水果的子类。这就是为什么它不会抛出异常,而这种行为是OOP的基础之一:它被称为多态性。 如果数组被声明为apple数组,并且您尝试在其中添加水果(与您的情况相反),那么将引发异常:因为您只能隐式地从子级转换到父级(从父级到子级的转换应该是显式的)

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

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

    首先声明数组,在本例中是一个水果数组

    然后创建数组,在本例中为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();
            }
        } 
    }
    
    类水果{}
    苹果类扩展水果{}
    类{}
    橙色类扩展水果{}
    公共类主{
    公共静态void main(字符串[]args){
    水果[]水果=新苹果[10];
    布尔alt=(Math.random()<0.5);
    试试{
    水果[0]=水果工厂(alt);
    }catch(异常e){System.out.println(e);}
    } 
    私人静态水果工厂(布尔苹果){
    如果(苹果){
    返回新苹果();
    }否则{
    返回新的橙色();
    }
    } 
    }
    
    该代码与您的相同,只是水果[0]由水果工厂方法赋值。编译器无法判断布尔alt是
    true
    还是
    false

    编译器缺少哪些信息来实现这一点 任务不可能吗

    如上所述-编译器无法判断赋值是否可行

    是否存在此类代码正确的情况,因此没有 是否引发ArrayStoreException


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

    从编译器的角度来看,这些语句是正确的,因为数组在Java中是协变的。请参阅。请注意,布洛赫认为数组的协变性是首选列表而非数组的原因(有效Java第二版,第25项),以一个与本问题中所述非常相似的示例作为开头。