考虑以下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泛型来防止此错误吗?
答案 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
但我认为这是你能做的最好的事情。
但从这个意义上讲,您可以清楚地看到Integer
与String
不匹配(反之亦然)。
请注意,这是一个记录在案的异常
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[])