Creating an array from a generic Java collection

Whilst working on Jaggregate, I ran into some surprises involving Java generics (shocking, no?).  Today's subject: turning a generic collection into an array.

The uppermost interface in Jaggregate's type hierarchy is Collection<E>.  We might wish to ask such a collection for an array of its elements.  If we don't really want to do anything with specific elements, we can simply define a toArray() method which answers an object of type Object[]:

interface Collection<E> {
    Object[] toArray();
}

If you do want to manipulate the elements, you really want something like:

interface Collection<E> {
    E[] toArray();
}

This method would need to create an array of the appropriate component type, populate the array, and return it.  However, at runtime, the information about the type of E is no longer around; it gets discarded (erased) during compilation.  Thus an invocation such as:

Collection<String> names;
String[] namesAsArray = names.toArray();

would raise a ClassCastException -- the best the runtime can do is create an Object[], which is-not-a String[], even if you try to cast the created array to E[] internally.

Fortunately, we can get around this problem by making the caller tell us what she wants the component type of the result to be:

interface Collection<E> {
    Object[] toArray( Class<? super E> componentType );
}

Now, the client can hand us a Class object that represents E or any one of its ancestors, and the runtime can create an array of the appropriate component type via java.lang.reflect.Array.newInstance(componentType,size()).  But wait, the return type of toArray() is still Object[].  The client has to downcast to, say, String[], but at least it will be a safe cast.

Can we do better?  We want the return type to be some array type where the array's component type is a specified ancestor of E.  Maybe making toArray() a generic method will help?

interface Collection<E> {
    <T> T[] toArray( Class<T super E> componentType );
}

Doesn't compile.

interface Collection<E> {
    <T,E extends T> T[] toArray( Class<T> componentType );
}

Doesn't compile either.

interface Collection<E> {
    <T super E> T[] toArray( Class<T> componentType );
}

Nope.  Bummer!

I resorted to a utility method:

class Collections {
    public static <T,E extends T> T[] toArray(
        final Collection<E> collection,
        final Class<T> componentType ) {
    }
}

Does anyone have a better idea?  Note that I'm not interested in having the client create the array to populate and pass it to toArray(), as java.util.Collection requires.

Written on February 7, 2005