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?
public <T> T[] toArray(T[] a)The toArray() method is used to get an array which contains all the elements in ArrayList object in proper sequence (from first to last element); the runtime type of the returned array is that of the specified array. If the list fits in the specified array, it is returned therein.
The toArray() method of ArrayList is used to return an array containing all the elements in ArrayList in the correct order.
The Java ArrayList toArray() method converts an arraylist into an array and returns it. The syntax of the toArray() method is: arraylist.toArray(T[] arr) Here, arraylist is an object of the ArrayList class.
The best and easiest way to convert a List into an Array in Java is to use the . toArray() method. Likewise, we can convert back a List to Array using the Arrays. asList() method.
From the javadocs:
Like the toArray() method, this method acts as bridge between array-based and collection-based APIs. Further, this method allows precise control over the runtime type of the output array, and may, under certain circumstances, be used to save allocation costs.
This means that the programmer is in control over what type of array it should be.
For example, for your ArrayList<Integer>
instead of an Integer[]
array you might want a Number[]
or Object[]
array.
Furthermore, the method also checks the array that is passed in. If you pass in an array that has enough space for all elements, the the toArray
method re-uses that array. This means:
Integer[] myArray = new Integer[myList.size()]; myList.toArray(myArray);
or
Integer[] myArray = myList.toArray(new Integer[myList.size()]);
has the same effect as
Integer[] myArray = myList.toArray(new Integer[0]);
Note, in older versions of Java the latter operation used reflection to check the array type and then dynamically construct an array of the right type. By passing in a correctly sized array in the first place, reflection did not have to be used to allocate a new array inside the toArray
method. That is no longer the case, and both versions can be used interchangeably.
It is declared generically so that you can write code such as
Integer[] intArray = list.toArray(new Integer[0]);
without casting the array coming back.
It is declared with the following annotation:
@SuppressWarnings("unchecked")
In other words, Java is trusting you to pass in an array parameter of the same type, so your error does not occur.
The reason why the method has this signature is because the toArray
API predates generics: the method
public Object[] toArray(Object[] a)
has been introduced as early as Java 1.2.
The corresponding generic that replaces Object
with T
has been introduced as a 100% backward-compatible option:
public <T> T[] toArray(T[] a)
Changing the signature to generic lets callers avoid the cast: prior to Java 5, callers needed to do this:
String[] arr = (String[])stringList.toArray(new String[stringList.size()]);
Now they can do the same call without a cast:
String[] arr = stringList.toArray(new String[stringList.size()]);
EDIT :
A more "modern" signature for the toArray
method would be a pair of overloads:
public <T> T[] toArray(Class<T> elementType)
public <T> T[] toArray(Class<T> elementType, int count)
This would provide a more expressive, and equally versatile, alternative to the current method signature. There is an efficient implementation of this, too, with Array.newInstance(Class<T>,int)
method in place. Changing the signature in this way would not be backward-compatible, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With