Aquí le mostramos cómo usar los genéricos para obtener una matriz del tipo que está buscando y al mismo tiempo preservar la seguridad de la fuente (a diferencia de las otras respuestas, que le devolverán una Objectmatriz o generarán advertencias en el momento de la compilación):
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];
}
}
Eso se compila sin advertencias y, como puede ver main, para cualquier tipo de declaración de instancia GenSet, puede asignar aa una matriz de ese tipo, y puede asignar un elemento aa una variable de ese tipo, lo que significa que la matriz y los valores en la matriz son del tipo correcto.
Funciona mediante el uso de literales de clase como tokens de tipo de tiempo de ejecución, como se explica en los Tutoriales de Java . Los literales de clase son tratados por el compilador como instancias de java.lang.Class. Para usar uno, simplemente siga el nombre de una clase con .class. Entonces, String.classactúa como un Classobjeto que representa la clase String. Esto también funciona para interfaces, enumeraciones, matrices de cualquier dimensión (p String[].class. Ej. ), Primitivas (p int.class. Ej. ) Y la palabra clave void( p void.class. Ej .).
Classen sí es genérico (declarado como Class<T>, donde Trepresenta el tipo que Classrepresenta el objeto), lo que significa que el tipo de String.classesClass<String> .
Entonces, cada vez que llama al constructor GenSet, pasa un literal de clase para el primer argumento que representa una matriz del GenSettipo declarado de la instancia (por ejemplo, String[].classparaGenSet<String> ). Tenga en cuenta que no podrá obtener una matriz de primitivas, ya que las primitivas no se pueden usar para variables de tipo.
Dentro del constructor, llamar al método castdevuelve el Objectargumento pasado emitido a la clase representada por el Classobjeto en el que se llamó el método. Llamar al método estático newInstanceen java.lang.reflect.Arraydevuelve como una Objectmatriz del tipo representado por el Classobjeto pasado como primer argumento y de la longitud especificada por el intpasado como segundo argumento. Llamar al método getComponentTypedevuelve un Classobjeto que representa el tipo de componente de la matriz representada por el Classobjeto en el que se llamó el método (por ejemplo , String.classpara String[].class, nullsi el Classobjeto no representa una matriz).
Esa última oración no es del todo precisa. Llamar String[].class.getComponentType()devuelve un Classobjeto que representa la clase String, pero su tipo es Class<?>, no Class<String>, por lo que no puede hacer algo como lo siguiente.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Lo mismo ocurre con cada método Classque devuelve unClass objeto.
Con respecto al comentario de Joachim Sauer sobre esta respuesta (no tengo suficiente reputación para comentarlo yo mismo), el ejemplo que usa el elenco T[]dará como resultado una advertencia porque el compilador no puede garantizar la seguridad de tipo en ese caso.
Editar con respecto a los comentarios de Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}