Here's how to use generics to get an array of precisely the type you’re looking for while preserving type safety (as opposed to the other answers, which will either give you back an Object
array or result in warnings at compile time):
import java.lang.reflect.Array;
public class GenSet<E> {
private E[] a;
public GenSet(Class<E[]> clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet<String> foo = new GenSet<String>(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
}
}
That compiles without warnings, and as you can see in main
, for whatever type you declare an instance of GenSet
as, you can assign a
to an array of that type, and you can assign an element from a
to a variable of that type, meaning that the array and the values in the array are of the correct type.
It works by using class literals as runtime type tokens, as discussed in the Java Tutorials. Class literals are treated by the compiler as instances of java.lang.Class
. To use one, simply follow the name of a class with .class
. So, String.class
acts as a Class
object representing the class String
. This also works for interfaces, enums, any-dimensional arrays (e.g. String[].class
), primitives (e.g. int.class
), and the keyword void
(i.e. void.class
).
Class
itself is generic (declared as Class<T>
, where T
stands for the type that the Class
object is representing), meaning that the type of String.class
is Class<String>
.
So, whenever you call the constructor for GenSet
, you pass in a class literal for the first argument representing an array of the GenSet
instance's declared type (e.g. String[].class
for GenSet<String>
). Note that you won't be able to get an array of primitives, since primitives can't be used for type variables.
Inside the constructor, calling the method cast
returns the passed Object
argument cast to the class represented by the Class
object on which the method was called. Calling the static method newInstance
in java.lang.reflect.Array
returns as an Object
an array of the type represented by the Class
object passed as the first argument and of the length specified by the int
passed as the second argument. Calling the method getComponentType
returns a Class
object representing the component type of the array represented by the Class
object on which the method was called (e.g. String.class
for String[].class
, null
if the Class
object doesn't represent an array).
That last sentence isn't entirely accurate. Calling String[].class.getComponentType()
returns a Class
object representing the class String
, but its type is Class<?>
, not Class<String>
, which is why you can't do something like the following.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Same goes for every method in Class
that returns a Class
object.
Regarding Joachim Sauer's comment on this answer (I don't have enough reputation to comment on it myself), the example using the cast to T[]
will result in a warning because the compiler can't guarantee type safety in that case.
Edit regarding Ingo's comments:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}