0

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:

 @SuppressWarnings("unchecked")
    public A(T element){

       List<T> datasList = new ArrayList<T>();
       datasList.add(element);
       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){....}.

3
  • 2
    You don't have to use a list but could try (T[])Array.newInstance(element.getClass(), 10). This will still generate the warning due to the cast but you can safely ignore that as long as element.getClass() is Class<T> (which it should be in most cases - unless T is defined by something else and element would be a subclass of the defined T). Commented Nov 8, 2016 at 12:20
  • @Thomas thanks. that would do the trick. Commented Nov 8, 2016 at 12:21
  • Nice option, I didn't think of this. Upvoted the comment Commented Nov 8, 2016 at 12:27

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Good point about the subclass, but in that case I would suggest adding "Class< T > clazz" instead of the T firstElement
@JeroenvanDijk yes that would be the safest way but would require a different api (which might be hard to change).
True (again) :)
0

You can pass generics, but you can't call new T (or new T[ ]). Keep in mind that generics are gone after compilation, so it actually only helps when writing the code. Knowing it's gone during runtime, it's also obvious that new T( ) can't be called as generic, T is removed in runtime.

It's safe to do, because you create that list in full control, accepting only objects of your generic type.

A nicer way (imho) is to create a static method as it is purely input-->output. You have to declare your generics before the method return type:

public < T > T[ ] toArray(T... objects) { ... }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.