Why does the Java Collection <E> .toArray () return an object [] rather than E []?

Prior to generating Java, Collection.toArray() had no way of knowing what type of array the developer was expecting (especially for an empty collection). As far as I understand, this was the main argument in favor of the idiom collection.toArray(new E[0]) .

With the generics Collection<E>.toArray() can return an array full of instances of E and / or its specializations. I wonder why the return type is still equal to Object[] , not E[] . In my opinion, returning E[] instead of Object[] should not violate existing code.

See: Collection.toArray() , Collection.toArray(T[]) and related java theme : (String []) List.toArray () provides a ClassCastException

+20
java collections generics toarray
May 30 '11 at 7:38 a.m.
source share
3 answers

This is a very good question. The answer is that generics are also called β€œerasures”. This is not just a name. Generically encoded information is only used at compile time and then deleted. Thus, the JVM does not even know this generic type E , so it cannot create an array E[] .

Another toArray(T[] a) method gets type information from an argument at runtime. For this reason, the prototype of this method is <T> T[] toArray(T[] a) : it receives an array of type T and can return an array of type T. The type is passed as a parameter.

+9
May 30 '11 at 7:44
source share

Erasing a type is just a partial explanation: neither the Collection method nor its toArray() have any information about E at run time.

In addition, due to backward compatibility, Collection.toArray() should return Object[] . Prior to Java 1.5, there was no way to find out the general type for a collection, so this was the only reasonable API design.

+5
May 30 '11 at 7:46 a.m.
source share

@Lukas, regarding: "new E []"

The new E [0] raised a compiler error, as you probably expected. The workaround I found is:

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

NB code is in the Listener <E extends Event> template class.

On my workaround, the erase type is both a problem and a solution. Casting to (E []) is safe because its exact type is erased before Event []. The only drawback that I see is the compiler warning about "unverified or unsafe operations" (which, obviously, in this case the cast does not work when the type is erased).

@Lukas, regarding backward compatibility

I do not see a big problem with backward compatibility. Creating a special return type is not the same as making the argument type more special.

In other words, the source code, which until now expected Collection.toArray () to return Object [], should be happy to get E [].

And as for the byte code, Object [] and E [] are the same anyway due to type erasure.

+1
May 30 '11 at 14:40
source share



All Articles