Convert a generic list to an array
I have searched for this, but unfortunately, I don't get the correct answer.
class Helper {
public static <T> T[] toArray(List<T> list) {
T[] array = (T[]) new Object[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
}
}
Test it:
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("abc");
String[] array = toArray(list);
System.out.println(array);
}
But there is an error thrown:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
at test.Helper.main(Helper.java:30)
How to solve this?
UPDATE
I want this method, because sometimes, the type in my code is too long:
newEntries.toArray(new IClasspathEntry[0])
I'd hope to call:
toArray(newEntries)
FINALLY
It seems impossible to create such a method, thank you all very much!
This is due to type erasure. The generics are removed in compilation, thus the Helper.toArray
will be compiled into returning an Object[]
.
For this particular case, I suggest you use List.toArray(T[])
.
String[] array = list.toArray(new String[list.size()]);
You can just call list.toArray(T[] array)
and not have to worry about implementing it yourself, but as aioobe said, you can't create an array of a generic type due to type erasure. If you need that type back, you need to create a typed instance yourself and pass it in.
If you want to produce your method through brute force, and you can guarantee that you'll only call the method with certain restrictions, you can use reflection:
public static <T> T[] toArray(List<T> list) {
T[] toR = (T[]) java.lang.reflect.Array.newInstance(list.get(0)
.getClass(), list.size());
for (int i = 0; i < list.size(); i++) {
toR[i] = list.get(i);
}
return toR;
}
This approach has problems. As list can store subtypes of T, treating the first element of the list as the representative type will produce a casting exception if your first element is a subtype. This means that T can't be an interface. Also, if your list is empty, you'll get an index out of bounds exception.
This should only be used if you only plan to call the method where the first element of the list matches the Generic type of the list. Using the provided toArray method is much more robust, as the argument provided tells what type of array you want returned.
You can't instantiate a Generic type like you did here:
T[] array = (T[]) new Object[list.size()];
As, if T
is bounded to a type, you're typecasting the new Object
array to a bounded type T
. I would suggest using List.toArray(T[])
method instead.
See Guava's Iterables.toArray(list, class)
.
Example:
@Test
public void arrayTest() {
List<String> source = Arrays.asList("foo", "bar");
String[] target = Iterables.toArray(source, String.class);
}