-1

According to here, the List<E>.toArray() method returns Object[]. It can't return T[] unless you use <T> T[] toArray(T[] a). Why cannot it return E[] since we declared it as List<E>?

Terry
  • 289
  • 1
  • 5
  • 12
  • 2
    My guess is type erasure (and possibly backwards compatibility, to some extent; I'd expect `toArray()` to have been around since the pre-generics days. Not really sure if changing it would have broken anything though due to erasure, and because arrays are covariant) – awksp Jun 16 '14 at 06:52
  • The caller is thus free to modify the returned array – Rod_Algonquin Jun 16 '14 at 06:52

2 Answers2

1

Long story short: type erasure (and backwards compatibility, to some extent).

Java's generics are implemented in a rather interesting way -- they exist only up until the compile phase, where they are used for type-checking. They are then removed in a process called type erasure, where each generic type is replaced with its upper bound (Object for unbounded types, such as for List<E> (note: there are a few exceptions, but those aren't really important in this case)

Thus, at runtime, generic classes actually don't know the exact type of object that the generic type is supposed to represent. As such, implementations of List<E> only know that they hold objects of type Object, not type E.

Therefore, it is actually impossible for toArray() to return E[], as the information needed to do such a thing isn't available at runtime. That is why toArray(T[]) exists -- T[] can only be returned if the type information required to do so is provided during runtime -- in this case, through the provided array, as arrays maintain knowledge of the types that they hold.


In addition, I suspect backwards compatibility was part of the reason why Object[] is returned. List has been around since the Collections API was introduced (1.2 or 1.3, I think), which was before generics were introduced (1.5). Thus, there was no E[] to return, as the mechanism to return that didn't exist yet. So perhaps for API stability and backwards compatibility the Object[] return type was kept.

I think changing Object[] to E[] wouldn't have broken any working code because arrays are covariant, but I'm not totally confident that that would have been the case.

awksp
  • 11,292
  • 4
  • 35
  • 44
-1

The ArrayList store the objects in an array. Calling toArray() returns a copy of that array.

The implementation is:

public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

Here the elementData is:

private transient Object[] elementData;

This is the array of objects in which the ArrayList stores it data.

To return T[] you need to use toArray(T[] a). You can simply pass a new array with type T.

This is the implementation in ArrayList:

public <T> T[] toArray(T[] a) {
    if (a.length < size)        
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());

    System.arraycopy(elementData, 0, a, 0, size);

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

    return a;
}

In case of LinkedList this method creates an Object[] then iterates all the nodes from the beginning and copies the element into that array. Here is the implementation:

public Object[] toArray() {
    Object[] result = new Object[size];
    int i = 0;

    for (Entry<E> e = header.next; e != header; e = e.next)
        result[i++] = e.element;

    return result;
}

Negative voters please comment.

Tapas Bose
  • 25,780
  • 71
  • 202
  • 317
  • 1
    What about `LinkedList`s? The question is about the method as declared in the `List` *interface*, not the `ArrayList` implementation. – awksp Jun 16 '14 at 06:55
  • @user3580294 please see my answer. – Tapas Bose Jun 16 '14 at 07:05
  • @user3580294 clearly `List` interface doesn't have any implementation, so we have to see the concrete implementation. – Tapas Bose Jun 16 '14 at 07:07
  • You still didn't address the question: *Why* does `toArray()` return `Object[]` rather than `E[]`? Saying "Because that's how it's implemented" is stupid; implementations follow specifications, not the other way around. – awksp Jun 16 '14 at 07:07
  • *The implementation doesn't matter for this question*. Specifications *define* implementations, and decisions about public interfaces and APIs should not (and are not, in this case) be based on available implementations. You're not addressing the *why* behind the specification decision. – awksp Jun 16 '14 at 07:09