为什么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的数组并且可以返回类型为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 []无论如何都是相同的。