Why does Java's Collection<E>.toArray() return an Object[] rather than an E[]?
Before Java generics, Collection.toArray()
had no way to know which type of array the developer expected (particularly for an empty collection). As I understand it, this was the main rationale behind the idiom collection.toArray(new E[0])
.
With generics, Collection<E>.toArray()
can only return an array full of instances of E
and/or its specialisations. I wonder why the return type still is as Object[]
rather than E[]
. In my opinion, returning an E[]
instead of Obje开发者_StackOverflow社区ct[]
should not break existing code.
See: Collection.toArray()
, Collection.toArray(T[])
and the related topic java: (String[])List.toArray() gives ClassCastException
It is a very good question. The answer is that generics are also called "erasures." It is not just a name. The information coded by generics is used at compile time only and then is removed. So, JVM even does not know this generic type E
, so it cannot create array E[]
.
Other method toArray(T[] a)
receives the information about the type from the argument at runtime. This is the reason this method's prototype is <T> T[] toArray(T[] a)
: it gets array of type T and can return array of type T. The type is passed as a parameter.
"Type erasure" is only a partial explanation: Neither the Collection
, nor its toArray()
method have any information about E
at run time.
It is also because of backwards compatibility, that Collection.toArray()
must still return Object[]
. Before Java 1.5, there was no way of knowing a generic type for a collection, so this was the only reasonable API design.
@Lukas, regarding: “new E[]”
The new E[0] raised the comiler error, as you probably expected. The workaround I have found is:
final E[] returnArray = (E[]) events.toArray( new Event[ events.size() ] );
N.B. the code is in a template class Listener<E extends Event>.
In my workaround, type erasure is both the problem and the solution. The cast to (E[]) is safe because its precise type is erased to Event[]. The only downside I see is the compiler warning about “unchecked or unsafe operations” (which, obviously, the cast is not in this case given type erasure).
@Lukas, regarding backward compatibility
I do not see a big problem with backward compatibility. Making the return type more special is not the same as making the argument type more special.
In other words, source code which so far expected Collection.toArray() to return an Object[] should be perfectly happy to receive an E[] instead.
And as to byte code, the Object[] and E[] are anyway the same due to type erasure.
精彩评论