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 Objectmatriz 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 aa 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.classatua como um Classobjeto 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 ).
Classem si é genérico (declarado como Class<T>, onde Trepresenta o tipo que o Classobjeto 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 GenSettipo declarado da instância (por exemplo, String[].classparaGenSet<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 castretorna o Objectargumento transmitido para a classe representada pelo Classobjeto no qual o método foi chamado. Chamar o método estático newInstanceem java.lang.reflect.Arrayretorna como uma Objectmatriz do tipo representado pelo Classobjeto passado como o primeiro argumento e do comprimento especificado pelo métodoint passado como o segundo argumento. Chamar o método getComponentTypedevolve um Classobjecto que representa o tipo de componente da matriz representada pelo Classobjecto em que o método foi chamado (por exemplo, String.classpara String[].class, nullse oClass objecto não representa uma matriz).
Essa última frase não é totalmente precisa. ChamandoString[].class.getComponentType() retorna um Classobjeto 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 Classque 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));
}