Ecco come utilizzare generics per ottenere un array esattamente del tipo che stai cercando, preservando la sicurezza del tipo (al contrario delle altre risposte, che ti restituiranno un Objectarray o genereranno avvisi al momento della compilazione):
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];
}
}
Questo si compila senza avvertimenti e, come puoi vedere main, per qualunque tipo tu dichiari un'istanza di GenSetas, puoi assegnarlo aa un array di quel tipo e puoi assegnare un elemento aa una variabile di quel tipo, il che significa che l'array e i valori nella matrice sono del tipo corretto.
Funziona usando i letterali di classe come token di tipo runtime, come discusso nei Tutorial Java . I letterali di classe vengono trattati dal compilatore come istanze di java.lang.Class. Per usarne uno, basta seguire il nome di una classe con .class. Quindi, String.classagisce come un Classoggetto che rappresenta la classe String. Questo funziona anche per interfacce, enumerazioni, array di qualsiasi dimensione (ad es. String[].class), Primitive (ad es. int.class) E la parola chiave void(ad es void.class.).
Classstesso è generico (dichiarato come Class<T>, dove Tsta per il tipo che l' Classoggetto rappresenta), nel senso che il tipo di String.classè Class<String>.
Quindi, ogni volta che si chiama il costruttore per GenSet, si passa in una classe letterale per il primo argomento che rappresenta una matrice del GenSettipo dichiarato dell'istanza (ad esempio String[].classper GenSet<String>). Nota che non sarai in grado di ottenere una matrice di primitive, poiché le primitive non possono essere utilizzate per le variabili di tipo.
All'interno del costruttore, chiamando il metodo viene castrestituito il Objectcast dell'argomento passato alla classe rappresentata Classdall'oggetto su cui è stato chiamato il metodo. La chiamata del metodo statico newInstancein java.lang.reflect.Arrayrestituisce come una Objectmatrice del tipo rappresentato Classdall'oggetto passato come primo argomento e della lunghezza specificata dal intpassato come secondo argomento. Chiamando il metodo getComponentTyperestituisce un Classoggetto che rappresenta il tipo di componenti della matrice rappresentata dalla Classoggetto su cui è stato chiamato il metodo (ad esempio String.classper String[].class, nullse l' Classoggetto non rappresenta un array).
L'ultima frase non è del tutto accurata. La chiamata String[].class.getComponentType()restituisce un Classoggetto che rappresenta la classe String, ma il suo tipo Class<?>non Class<String>è, motivo per cui non è possibile eseguire operazioni come le seguenti.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Lo stesso vale per ogni metodo Classche restituisce un Classoggetto.
Per quanto riguarda il commento di Joachim Sauer su questa risposta (non ho abbastanza reputazione per commentarlo da solo), l'esempio che usa il cast per T[]genererà un avviso perché il compilatore non può garantire la sicurezza del tipo in quel caso.
Modifica in merito ai commenti di Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}