【问题标题】:Why there is no ArrayStoreException thrown in below code?为什么下面的代码中没有抛出 ArrayStoreException?
【发布时间】:2015-05-03 13:17:52
【问题描述】:
private static void genericArrayTest() {
    ArrayList<? extends Exception>[] exceptionListArray = new ArrayList[10]; 
    Object[] exceptionObjectListArray  = exceptionListArray;

    ArrayList<String> wrongArrayList = new ArrayList<String>();
    wrongArrayList.add("String One");

    ArrayList<NullPointerException> exceptionList = new ArrayList<>();

    ArrayList rawList = new ArrayList();

    exceptionListArray[0] = exceptionList;
    //exceptionListArray[0] = wrongArrayList; // Compile error?
    //exceptionListArray[0] = rawList;

    exceptionObjectListArray[0] = wrongArrayList; 
// No compile time error, there is no ArrayStoreException why ?

    ArrayList<? extends Exception> list = exceptionListArray[0]; // No exception here as well ??
    Exception e = list.get(0); 
// Exception only when accessing data, why not ArrayStoreException when we stored wrong list ??
    System.out.println();
}

谁能解释一下这是怎么回事?

谷歌搜索说下面的数组声明是允许的
ArrayList&lt;Exception&gt;[] exceptionListArray = new ArrayList[10];
但不是这个
ArrayList&lt;Exception&gt;[] exceptionListArray = new ArrayList&lt;Exception&gt;[10];
这两个声明有什么区别?为什么一个不允许另一个?

Creating an array to store generic types in Java 讨论如何创建泛型数组。但是这个问题不是关于如何创建泛型数组,而是关于为什么在运行时不抛出 ArrayStoreException 以及 java 中泛型数组创建语法的差异

【问题讨论】:

  • 在此处查看您的最后一个问题:stackoverflow.com/a/16415586/986169。关于 exceptionObjectListArray,它被声明为 Object 类型的数组。因此,任何扩展 Object 的类型的数组都可以分配给它。
  • @giorashc 从上面的链接,我进入了 - docs.oracle.com/javase/tutorial/java/generics/…。它说“如果允许参数化列表的数组,代码将无法抛出所需的 ArrayStoreException”。但是,它现在也发生了,上面的代码块正确吗?所以问题是 java 通过允许 'ArrayList[] exceptionListArray = new ArrayList[10]; 实现了什么? ' ?
  • 我不认为这是完全重复的,因为这个问题询问的是 ArrayStoreException。

标签: java arrays generics


【解决方案1】:

在 Java 中,泛型参数化没有一个类来区分它们:

ArrayList<Exception> : class is ArrayList
ArrayList<String>    : class is ArrayList

这是因为泛型是用type erasure实现的,也就是说在编译的时候,它们会被强制转换:

ArrayList<Exception> list = new ArrayList<Exception>();
list.add(new Exception());
Exception e = list.get(0);

变成:

ArrayList list = new ArrayList();
list.add(new Exception());
Exception e = (Exception) list.get(0);

没有ArrayStoreException 被抛出,因为ArrayList&lt;Exception&gt;ArrayList&lt;String&gt; 在程序执行期间具有相同的类型。

不允许使用泛型数组,因为在执行期间无法对类型参数执行这些检查。 (因为类型参数不存在了。)

当我们有这个时:

ArrayList<Exception>[] a =
    new ArrayList[10];

这称为未经检查的转换。 a 实际上是一个ArrayList[],一个存储任何ArrayList 的数组,但我们基本上说过“暂时假设它是一个ArrayList&lt;Exception&gt;[]a 指向的数组对象仍然是ArrayList[]


看下面的程序来说明:

import java.util.*;

class Example {
    public static void main(String[] args) {
        ArrayList<Exception> a = new ArrayList<Exception>();
        ArrayList<String>    b = new ArrayList<String>();

        System.out.println("ArrayList<Exception> class is:");
        System.out.println("\t" + a.getClass());
        System.out.println("ArrayList<String> class is:");
        System.out.println("\t" + b.getClass());
        System.out.println(
            "ArrayList<Exception> class == ArrayList<String> class:");
        System.out.println("\t" + ( a.getClass() == b.getClass() ));

        ArrayList<Exception>[] c = new ArrayList[0];
        ArrayList<String>[]    d = new ArrayList[0];

        System.out.println("ArrayList<Exception>[] class is:");
        System.out.println("\t" + c.getClass());
        System.out.println("ArrayList<String>[] class is:");
        System.out.println("\t" + d.getClass());
        System.out.println(
            "ArrayList<Exception>[] class == ArrayList<String>[] class:");
        System.out.println("\t" + ( c.getClass() == d.getClass() ));
    }
}

http://ideone.com/dfCZjy

输出:

ArrayList<Exception> class is:
    class java.util.ArrayList
ArrayList<String> class is:
    class java.util.ArrayList
ArrayList<Exception> class == ArrayList<String> class:
    true
ArrayList<Exception>[] class is:
    class [Ljava.util.ArrayList;
ArrayList<String>[] class is:
    class [Ljava.util.ArrayList;
ArrayList<Exception>[] class == ArrayList<String>[] class:
    true

【讨论】:

  • 类型擦除与否,Java 中的每个类都扩展自Object。我想这应该足以解释为什么没有抛出 ArrayStoreException
  • @ChetanKinger 我真的不明白这有什么关系。
  • @ChetanKinger 这无关紧要,因为exceptionObjectListArray 的类是ArrayList[],而不是Object[]。可以为编译时类型为Object[] 的数组获取ArrayStoreException
  • @pbabcdefp 你能详细说明the class of exceptionObjectListArray is ArrayList[] 的意思吗?你的意思是在运行时,因为在编译时,它是一个 Object[] 数组,对吗?
猜你喜欢
  • 2011-10-15
  • 1970-01-01
  • 2014-10-26
  • 2019-01-09
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多