Veja como usar os genéricos para obter uma matriz precisamente do tipo que você procura, preservando a segurança do tipo (ao contrário das outras respostas, que lhe devolvem uma Object
matriz ou resultam em avisos em tempo de compilação):
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];
}
}
Isso é compilado sem avisos e, como você pode ver main
, para qualquer tipo de declaração de instância GenSet
, você pode atribuir a
a uma matriz desse tipo e atribuir um elemento dea
a uma variável desse tipo, o que significa que a matriz e os valores na matriz são do tipo correto.
Ele funciona usando literais de classe como tokens de tipo de tempo de execução, conforme discutido no Tutoriais Java . Literais de classe são tratados pelo compilador como instâncias de java.lang.Class
. Para usar um, basta seguir o nome de uma classe com .class
. Então, String.class
atua como um Class
objeto representando a classe String
. Isso também funciona para interfaces, enumerações, matrizes unidimensionais (por exemplo String[].class
), primitivas (por exemplo int.class
) e a palavra-chave void
( por exemplo ,void.class
).
Class
em si é genérico (declarado como Class<T>
, onde T
representa o tipo que o Class
objeto está representando), o que significa que o tipo de String.class
éClass<String>
.
Portanto, sempre que você chama o construtor GenSet
, transmite uma classe literal para o primeiro argumento que representa uma matriz do GenSet
tipo declarado da instância (por exemplo, String[].class
paraGenSet<String>
). Observe que você não poderá obter uma matriz de primitivas, pois as primitivas não podem ser usadas para variáveis de tipo.
Dentro do construtor, chamar o método cast
retorna o Object
argumento transmitido para a classe representada pelo Class
objeto no qual o método foi chamado. Chamar o método estático newInstance
em java.lang.reflect.Array
retorna como uma Object
matriz do tipo representado pelo Class
objeto passado como o primeiro argumento e do comprimento especificado pelo métodoint
passado como o segundo argumento. Chamar o método getComponentType
devolve um Class
objecto que representa o tipo de componente da matriz representada pelo Class
objecto em que o método foi chamado (por exemplo, String.class
para String[].class
, null
se oClass
objecto não representa uma matriz).
Essa última frase não é totalmente precisa. ChamandoString[].class.getComponentType()
retorna um Class
objeto que representa a classe String
, mas seu tipo Class<?>
não é , Class<String>
e é por isso que você não pode fazer algo como o seguinte.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
O mesmo vale para todos os métodos Class
que retornam umClass
objeto.
Sobre o comentário de Joachim Sauer em esta resposta (eu não tenho reputação suficiente para comentar sobre ela), o exemplo do uso do elenco T[]
resultará em um aviso, pois o compilador não pode garantir a segurança do tipo nesse caso.
Edite sobre os comentários de Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}