alainlompo alainlompo - 10 months ago 55
Java Question

Generic list conversion to an array

Assuming that I have the following class

public class A <T>{

private T [] datas;
// more code here ...

And I desire to take advantage of the constructor to initialize the array. Suppose that I have the following constructor

public A(T element){....}

Java does not allow me to use something like

datas = new T[10]

And it will complain that I cannot create a generic array of T
But I can still use a work around like:

public A(T element){

List<T> datasList = new ArrayList<T>();
datas =(T[]) datasList.toArray();

I have a warning from the compiler that's why I had to add the @SuppressWarnings, but my point is related to the following comment from the toArray method documentation (Please take a look at the picture)

enter image description here

It talks about the returned array being safe. So does that means it is safe to use this method? If not why? And what would be a better way to do such an initialisation in a constructor? I would like to also consider the case of a variable list of T elements in an overloaded constructor like

public A(T... elements){....}.

Answer Source

You can create an instance of a generic array using the following:

public A(T element){
  int length = 10;
  datas  = (T[])Array.newInstance(element.getClass(), length);

However, there's a problem if element would be a subclass of T, e.g. if you'd call it like this:

A<Number> numberA = new A<>( Integer.valueOf(1) );

Here T would be Number but the class of element would be Integer. To mitigate that you could pass a vararg array of type T, e.g. like this:

//firstElement only exists to force the caller to provide at least one element
//if you don't want this then just use the varargs array
A(T firstElement, T... furtherElements){      
  int length = 10;
  Class<?> elementClass = furtherElements.getClass().getComponentType();      
  datas  = (T[])Array.newInstance( elementClass, length);

Since varargs always result in an array (even of length 0) you'll get an array of type T and can get the component type of that.

So in the case above numberA.datas would be a Number[] array and not an Integer[] array.