为什么Java的Collection .toArray()返回一个Object 而不是一个E ?

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

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

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

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

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

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

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

@Lukas,关于:“新E []”

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

final E [] returnArray = (E [])events.toArray(new Event [events.size()]);

注意,代码在模板类Listener 中。

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

@Lukas,关于向后兼容性

我没有看到向后兼容性的大问题。 使返回类型更特殊与使参数类型更特殊不同。

换句话说,到目前为止期望Collection.toArray()返回Object []的源代码应该非常乐意接收E []。

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