I was just looking at the method defined in the List interface: <T> T[] toArray(T[] a)
, and I have a question. Why is it generic? Because of that fact, method is not complete type-safe. The following code fragment compiles but causes ArrayStoreException
:
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
String[] stringArray = list.toArray(new String[]{});
It seems to me if toArray was not generic and took List type parameter, it would be better.
I have written toy example and it is ok witout generic:
package test;
import java.util.Arrays;
public class TestGenerics<E> {
private Object[] elementData = new Object[10];
private int size = 0;
public void add(E e) {
elementData[size++] = e;
}
@SuppressWarnings("unchecked")
//I took this code from ArrayList but it is not generic
public E[] toArray(E[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (E[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
public static void main(String[] args) {
TestGenerics<Integer> list = new TestGenerics<Integer>();
list.add(1);
list.add(2);
list.add(3);
//You don't have to do any casting
Integer[] n = new Integer[10];
n = list.toArray(n);
}
}
Is there any reason why it is declared that way?
a
. It serves as a type token, telling the method what type of array to create. It's up to you to pass the correct type there. Otherwise the only thing the method could return is anObject[]
. – FilbertList
instance has no idea what its item type is, so doing so automatically is impossible. – FilbertList
beforehand. The compiler can statically prove the code is type safe for those. – FilbertString[]
to aObject[]
but avoid being able to write not-type-safe code this way. The collections API then punted on this until the introduction of generics.) If you tried to donew T[]
the compiler wouldn't know what to use as this runtime data. – Filbert