2

Why does Collection<E>.toArray() (non-parameterized method) return Object[]?

Is it one of those consciously taken decisions? Is there any reason why the toArray() method would not be able to return a E[], if it wanted to?

jrharshath
  • 23,967
  • 32
  • 94
  • 126
  • type erasure is the reason. java does not know what T is at runtime - therefore it cannot create an array of the appropriate type. The other, "typesafe" variant of toArray requires a "prototype" array with the right type (that is fixed at compile time!) which it can copy. – Pyranja Feb 23 '13 at 07:24
  • It's historical. The method predates generics, and was kept in its existing form to avoid breaking legacy code. – Perception Feb 23 '13 at 07:25
  • I'm not so sure about that. I don't see any way to get the class of `E` in that method. – Andrew Mao Feb 23 '13 at 07:28
  • possible duplicate of [Why does Java's Collection.toArray\(\) return an Object\[\] rather than an E\[\]?](http://stackoverflow.com/questions/6173495/why-does-javas-collectione-toarray-return-an-object-rather-than-an-e). Please ignore the post I gave when voting - I pasted the wrong link. – Paul Bellora Feb 23 '13 at 18:06

3 Answers3

6

It's because an array of type T cannot be instantiated without knowing the type Class<T>. Contrast this with toArray(T[] array), which has the following source (example from LinkedList). Notice that the passed-in array is used not only as a possible container, but to possibly instantiate a new array of that type. This code throws an exception if T is not a superclass of E; if objects can't be added to the array.

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        a = (T[])java.lang.reflect.Array.newInstance(
                            a.getClass().getComponentType(), size);
    int i = 0;
    Object[] result = a;
    for (Node<E> x = first; x != null; x = x.next)
        result[i++] = x.item;

    if (a.length > size)
        a[size] = null;

    return a;
}
Andrew Mao
  • 31,800
  • 17
  • 126
  • 212
1

Generics in Java are implemented using a technique called type erasure. This means that an instance of a generic class does not have any information about its generic type. Consider this

List<String> list = new ArrayList<String>();
list.toArray();

since list does not know about its generic type it can create only Object[]

Evgeniy Dorofeev
  • 124,221
  • 27
  • 187
  • 258
0

Array containers have an associated item data type, preserved at runtime. If you construct an Object array and then add strings, this object won't be castable to String[]:

    Object[] objArr = new Object[] {"a", "b"};
    String[] strArr = (String[]) objArr; //Produces ClassCastException

You can also notice how this array property is used at runtime when you add items of an incorrect type to an array:

    String[] strArr = new String[] {"a", "b"};
    Object[] objArr = (Object[]) strArr; //Legal this time
    objArr[0] = 15; //Produces ArrayStoreException

Generic type arguments are erased at runtime, so the JVM doesn't know what specific array type to create at runtime when you call toArray().

Eyal Schneider
  • 21,096
  • 4
  • 43
  • 73