考虑一下下面对Java的ArrayList#toArray方法的测试。请注意,我从这个有用的回答中借用了代码。
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放入一个String[]中时,会有一个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泛型在编译时防止此错误?
发布于 2014-02-18 16:20:37
ArrayStoreException之所以存在,正是因为它的类型系统无法正确地处理这种情况(IIRC,当Generics出现时,用与集合框架相同的方式对数组进行修改已经太晚了)。
因此,在编译时通常无法防止此问题的发生。
当然,您可以创建内部API来包装这些操作,以减少意外错误类型的可能性。
另请参阅:
发布于 2014-02-18 16:09:42
List#toArray(T[])是一个泛型方法,声明为
<T> T[] toArray(T[] a);因此,类型参数要么是从给定数组的类型推断出来的,要么是以<Type>符号作为方法调用的前缀。
所以你可以
String[] baz = foo.<Integer>toArray(new String[10]); // doesn't compile但我觉得这是你能做的最好的了。
但从这个意义上说,您可以清楚地看到Integer与String不匹配(反之亦然)。
请注意,这是一个记录在案的异常。
ArrayStoreException -如果指定数组的运行时类型不是此列表中每个元素的运行时类型的超级类型
所以我不认为你应该在编译时找到它。
发布于 2014-02-18 18:22:24
由于兼容性原因,无法更改方法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]);由于前泛型,“String[]是Object[]的子类”规则。这不能用现有的Java语言解决。
https://stackoverflow.com/questions/21859099
复制相似问题