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 Object
matriz 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 a
a una matriz de ese tipo, y puede asignar un elemento a
a 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.class
actúa como un Class
objeto 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 .).
Class
en sí es genérico (declarado como Class<T>
, donde T
representa el tipo que Class
representa el objeto), lo que significa que el tipo de String.class
esClass<String>
.
Entonces, cada vez que llama al constructor GenSet
, pasa un literal de clase para el primer argumento que representa una matriz del GenSet
tipo declarado de la instancia (por ejemplo, String[].class
paraGenSet<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 cast
devuelve el Object
argumento pasado emitido a la clase representada por el Class
objeto en el que se llamó el método. Llamar al método estático newInstance
en java.lang.reflect.Array
devuelve como una Object
matriz del tipo representado por el Class
objeto pasado como primer argumento y de la longitud especificada por el int
pasado como segundo argumento. Llamar al método getComponentType
devuelve un Class
objeto que representa el tipo de componente de la matriz representada por el Class
objeto en el que se llamó el método (por ejemplo , String.class
para String[].class
, null
si el Class
objeto no representa una matriz).
Esa última oración no es del todo precisa. Llamar String[].class.getComponentType()
devuelve un Class
objeto 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 Class
que 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));
}