16.10.1. Genericity and Dynamic Arrays
Recall the toArray method of the SingleLinkQueue class from Chapter 11. We promised back then
that we'd show you how to create the array directly (instead of having it passed in) by having the type token
for the actual type argument of the queue passed in. Here's a first attempt:
public E[] toArray_v1(Class
int size = size();
E[] arr = (E[]) Array.newInstance(type, size);
int i = 0;
for (Cell
c != null && i < size;
c = c.getNext())
arr[i++] = c.getElement();
return arr;
}
This code works, but is less desirable than the generic version that took in the array to fill. The main problem
is that the above causes an "unchecked" warning from the compiler. As you may have already noticed, the
cast to E[] is a cast involving a type parameter and such casts have a different meaning at runtimethe actual
cast will be to Object, which is the erasure of E. Despite this, it is apparent that the code above is type-safe:
We ask for an array that has a component type of E and we try to use the returned object as such an array. The
existence of the "unchecked" warning is a consequence of a limitation in the Array API and can't be
avoided.
The second problem with the above is that it suffers from the same limitation as the original non-generic
version of toArrayit will only allow an array of the exact element type to be created, not an array of any
supertype. We can address this latter problem by turning the current version into a generic method, as we did
previously:
public
int size = size();
T[] arr = (T[]) Array.newInstance(type, size);
int i = 0;
Object[] tmp = arr;
for (Cell
c != null && i < size;
c = c.getNext())
tmp[i++] = c.getElement();
return arr;
}
This version still has the "unchecked" warningthat can't be avoidedbut it allows any Class object to passed
in and tries to return an array with that component type. As with the generic version that takes the array as an
argument, this version relies on the runtime checking of array stores to ensure that the component type passed
is actually compatible with the element type of the current queue.
So you're left with two approaches for dealing with the toArray requirement: have the caller pass in the
array and avoid warnings, but be forced to deal with an array of the wrong size, or have the caller pass in the
type token for the element type and create an array of the right size, but be subjected to the "unchecked"
warning. Or you could do as the collection classes do and combine both: Take in an array, but if it is the
wrong size dynamically create another one, and get the warning. While we normally advise that you avoid
"unchecked" warnings at all costs, the case of Array.newInstance is an exception.[5]