So verwenden Sie Generika, um ein Array mit genau dem Typ zu erhalten, nach dem Sie suchen, während die Typensicherheit erhalten bleibt (im Gegensatz zu den anderen Antworten, die Ihnen entweder ein Object
Array zurückgeben oder beim Kompilieren zu Warnungen führen):
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];
}
}
Dies wird ohne Warnungen kompiliert, und wie Sie in sehen können main
, können Sie für jeden Typ, für den Sie eine Instanz GenSet
als deklarieren a
, einem Array dieses Typs zuweisen und ein Element aus zuweisena
zu einer Variable dieses Typs, dass das Array bedeutet und die Werte im Array sind vom richtigen Typ.
Es funktioniert mit Klassenliteralen als Laufzeit-Token, wie in den Java-Tutorials beschrieben . Klassenliterale werden vom Compiler als Instanzen von behandelt java.lang.Class
. Um eine zu verwenden, folgen Sie einfach dem Namen einer Klasse mit .class
. So String.class
wirkt wie ein Class
Objekt der Klasse darstellt String
. Dies funktioniert auch für Schnittstellen, Aufzählungen, beliebige dimensionale Arrays (z. B. String[].class
) , Grundelemente (z. B. int.class
) und das Schlüsselwort void
(dh void.class
).
Class
selbst ist generisch (deklariert als Class<T>
, wobei T
für den Typ steht, den das Class
Objekt darstellt), was bedeutet, dass der Typ von String.class
istClass<String>
.
Wenn Sie also den Konstruktor für aufrufen GenSet
, übergeben Sie ein Klassenliteral für das erste Argument, das ein Array des GenSet
deklarierten Typs der Instanz darstellt (z. B. String[].class
fürGenSet<String>
. ). Beachten Sie, dass Sie kein Array von Grundelementen abrufen können, da Grundelemente nicht für Typvariablen verwendet werden können.
Innerhalb des Konstruktors gibt der Aufruf der Methode cast
das übergebene Object
Argument an die Klasse zurück, die durch das Class
Objekt dargestellt wird, für das die Methode aufgerufen wurde. Das Aufrufen der statischen Methode newInstance
in java.lang.reflect.Array
gibt als Object
Array den Typ zurück, der durch das Class
als erstes Argument übergebene Objekt und die durch das int
als zweites Argument übergebene Länge angegebene Länge dargestellt wird . Der Aufruf der Methode getComponentType
Gibt ein Class
Objekt den Komponententyp des Arrays von dem dargestellten darstellt Class
Objekt , auf dem das Verfahren aufgerufen wurde (zB String.class
für die String[].class
, null
wenn dieClass
Objekt nicht ein Array darstellt).
Dieser letzte Satz ist nicht ganz richtig. Beim Aufrufen wird String[].class.getComponentType()
ein Class
Objekt zurückgegeben, das die Klasse darstellt String
, sein Typ jedoch Class<?>
nicht Class<String>
. Aus diesem Grund können Sie Folgendes nicht ausführen.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Gleiches gilt für jede Methode Class
, die ein Class
Objekt zurückgibt .
In Bezug auf Joachim Sauers Kommentar zu dieser Antwort (ich habe nicht genug Ruf, um sie selbst zu kommentieren) führt das Beispiel, in dem die Besetzung verwendet T[]
wird, zu einer Warnung, da der Compiler in diesem Fall keine Typensicherheit garantieren kann.
Bearbeiten Sie die Kommentare von Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}