在编译时捕获ArrayStoreException

时间:2014-02-18 16:06:21

标签: java generics

考虑以下Java的ArrayList#toArray方法测试。请注意,我从这个有用的answer借用了代码。

public class GenericTest {
    public static void main(String [] args) {
        ArrayList<Integer> foo = new ArrayList<Integer>();
        foo.add(1);
        foo.add(2);
        foo.add(3);
        foo.add(4);
        foo.add(5);
        Integer[] bar = foo.toArray(new Integer[10]);
        System.out.println("bar.length: " + bar.length);

        for(Integer b : bar) { System.out.println(b); }

        String[] baz = foo.toArray(new String[10]);       // ArrayStoreException
        System.out.println("baz.length: " + baz.length);
    }
}

但是,请注意,在尝试将ArrayStoreException放入Integer时会有String[]

输出:

$>javac GenericTest.java && java -cp . GenericTest
bar.length: 10
1
2
3
4
5
null
null
null
null
null
Exception in thread "main" java.lang.ArrayStoreException
        at java.lang.System.arraycopy(Native Method)
        at java.util.ArrayList.toArray(Unknown Source)
        at GenericTest.main(GenericTest.java:16)

编译时可以通过Java泛型来防止此错误吗?

4 个答案:

答案 0 :(得分:7)

ArrayStoreException正是因为Java的类型系统无法正确处理这种情况(IIRC,当Generics出现时,以与集合框架相同的方式改造数组已经太晚了。)

因此,在编译时通常无法阻止此问题。

您当然可以创建内部API来包装此类操作,以减少意外获取类型错误的可能性。

另见:

答案 1 :(得分:2)

List#toArray(T[])是声明为

的泛型方法
<T> T[] toArray(T[] a);

因此,类型参数可以从给定数组的类型推断出来,也可以通过方法调用前缀<Type>表示法来推断。

所以你可以做到

String[] baz = foo.<Integer>toArray(new String[10]); // doesn't compile

但我认为这是你能做的最好的事情。

但从这个意义上讲,您可以清楚地看到IntegerString不匹配(反之亦然)。

请注意,这是一个记录在案的异常

  

ArrayStoreException - 如果指定数组的运行时类型是   不是此列表中每个元素的运行时类型的超类型

所以我认为你不应该在编译时试图找到它。

答案 2 :(得分:0)

出于兼容性原因,无法更改方法Collection.toArray

但是对于您自己的代码,您可以创建一个(更多)类型安全的帮助方法,如果您使用您的方法,可以保护您免受ArrayStoreException的影响:

public static <T> T[] toArray(List<? extends T> list, T[] t) {
    return list.toArray(t);
}

此方法将拒绝与您的问题的示例案例匹配的String[] s=toArray(new ArrayList<Integer>(), new String[0]);,但请注意数组子类型规则:它不会拒绝

Object[] s=toArray(new ArrayList<Integer>(), new String[0]);

因为前Generics“String[]Object[]”规则的子类。使用现有的Java语言无法解决这个问题。

答案 3 :(得分:0)

ArrayStoreException是运行时异常,不是编译时间,在运行时抛出,it表示不同类型的对象存储在数组中。     Object x [] = new String [3];          x [0] = new Integer(0); 在编译时可以找到它的唯一方法是使用&lt; Integer &gt;输入如下

foo.<Integer>toArray(new String[10]); 

上面会抛出编译时错误 The parameterized method <Integer>toArray(Integer[]) of type List<Integer> is not applicable for the arguments (String[])