20

在 Java 泛型之前,Collection.toArray()无法知道开发人员期望使用哪种类型的数组(尤其是对于空集合)。据我了解,这是成语背后的主要理由collection.toArray(new E[0])

使用泛型,Collection<E>.toArray()只能返回一个充满实例E和/或其特化的数组。我想知道为什么返回类型仍然是 asObject[]而不是E[]. 在我看来,返回一个E[]而不是不Object[]应该破坏现有的代码。

请参阅:Collection.toArray()Collection.toArray(T[])以及相关主题java: (String[])List.toArray() 给出 ClassCastException

4

3 回答 3

9

这是一个很好的问题。答案是泛型也称为“擦除”。它不仅仅是一个名字。泛型编码的信息仅在编译时使用,然后被删除。所以,JVM 甚至不知道这个泛型类型E,所以它不能创建数组E[]

其他方法toArray(T[] a)在运行时从参数接收有关类型的信息。这就是该方法的原型的原因<T> T[] toArray(T[] a):它获取类型为 T 的数组,并且可以返回类型为 T 的数组。类型作为参数传递。

于 2011-05-30T07:44:32.033 回答
5

“类型擦除”只是部分解释:Collection及其toArray()方法都没有关于E运行时的任何信息。

也是因为向后兼容,它Collection.toArray()仍然必须返回Object[]。在 Java 1.5 之前,无法知道集合的泛型类型,因此这是唯一合理的 API 设计。

于 2011-05-30T07:46:59.600 回答
1

@Lukas,关于:“新 E[]”</p>

正如您可能预期的那样,新的 E[0] 引发了编译器错误。我发现的解决方法是:

最终 E[] 返回数组 = (E[]) events.toArray( new Event[ events.size() ] );

注意代码在模板类Listener<E extends Event>中。

在我的解决方法中,类型擦除既是问题也是解决方案。转换为 (E[]) 是安全的,因为它的精确类型被擦除为 Event[]。我看到的唯一缺点是关于“未经检查或不安全的操作”的编译器警告(显然,在这种情况下,强制转换不是给定类型擦除)。

@Lukas,关于向后兼容性

我认为向后兼容性没有什么大问题。使返回类型更特殊与使参数类型更特殊不同。

换句话说,到目前为止期望 Collection.toArray() 返回 Object[] 的源代码应该很高兴收到 E[] 。

至于字节码,由于类型擦除, Object[] 和 E[] 无论如何都是相同的。

于 2011-05-30T14:40:41.963 回答