java:(String [])List.toArray()给出ClassCastException


107

以下代码(在android中运行)始终在第三行中给我ClassCastException:

final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();

当v2为Object [0]以及其中包含字符串时,也会发生这种情况。知道为什么吗?


您可能需要阅读有关协变和逆变- en.wikipedia.org/wiki/...
Hut8

如果T是带有工厂实例化接口的接口,那该怎么办?
sebaj 2011年

2
@LaceCard-这仅与协方差/反方差非常间接相关。真正的问题是,这是toArray()方法指定行为的直接结果。
斯蒂芬·C

Answers:


249

这是因为当您使用

 toArray() 

它返回一个Object [],该对象不能转换为String [](即使内容为String),这是因为toArray方法仅获得一个

List 

并不是

List<String>

因为泛型仅是源代码,在运行时不可用,因此无法确定要创建哪种类型的数组。

toArray(new String[v2.size()]);

分配正确类型的数组(String []和正确大小)


3
因为使用非专利药,这就是为什么
Kaleb Brasee

2
@Kaleb-不正确。或至少这不是最初的原因。这些toArray方法在收集类是通用的之前就已经存在。
Stephen C

10
这是正确的解决方案,但不是正确的解释。您不能将Object []转换为Double [],因为它是语言功能,仅此而已。它与泛型无关。您可以将Object转换为Double,前提是它确实是Double。因此,从逻辑上讲,您可以对数组执行相同的操作,但它根本不是语言的一部分。如果将Object强制转换为Double,则将进行运行时检查,以确保Object实际上是Double。如果将Double转换为Object,则不会进行运行时检查,因为Object在Double的继承层次结构中。
KyleM

5
在IntelliJ中执行此操作时,我得到一个警告,toArray(new String[0])而不是使用:“在较早的Java版本中,建议使用预先设置大小的数组,因为创建适当大小的数组所必需的反射调用非常慢。但是,由于OpenJDK的更新较晚6此调用很吸引人,使空数组版本的性能相同,有时甚至更好。另外,传递预大小的数组对于并发收集是危险的,因为sizeand toArray调用之间可能会发生竞争。”
Mikepote

35

您使用的是错误的 toArray()

请记住,Java的泛型大部分是语法糖。ArrayList实际上并不知道其所有元素都是字符串。

要解决您的问题,请致电toArray(T[])。就你而言

String[] v3 = v2.toArray(new String[v2.size()]);

请注意,通用形式toArray(T[])返回T[],因此不需要显式转换结果。


1
String[] v3 = v2.toArray(new String[0]); 

也可以做到这一点,请注意,一旦为方法指定了正确的ArrayType,您甚至不需要转换。


0
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

这样使用。


1
请!格式化您的代码!按“ ctrl + k”将其全部选中,或者在代码的第一个字母之前和最后一个字母之间添加“`”。编写答案时,也可以在顶部的帮助中选择“ {}”!
MK
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.