Cela peut être un peu tard pour la durée de votre affectation, climatewarrior, mais pour ceux qui s'intéressent à l'utilisation de génériques pour obtenir un tableau d'précisément le type que vous cherchez, tout en préservant la sécurité de type (par opposition a d'autres suggestions, qui seront soit vous redonner un Object
tableau ou d'entraîner des avertissements lors de la compilation), je pense que j'ai trouvé une solution.
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];
}
}
Qui compile sans mise en garde, et comme vous pouvez le voir en main
, quel que soit le type de vous déclarer une instance d' GenSet
comme, vous pouvez affecter a
pour un tableau de ce type, et vous pouvez affecter un élément à partir d' a
d'une variable de ce type, ce qui signifie que le tableau et les valeurs dans le tableau sont du type correct.
Il fonctionne en utilisant la classe des littéraux d'exécution jetons de type, tel que discuté dans la Java des Tutoriels. Classe littéraux sont traités par le compilateur comme des instances de java.lang.Class
. Pour en utiliser un, il suffit de suivre le nom d'une classe avec .class
. Donc, String.class
des actes en tant que Class
objet représentant la classe - String
. Cela fonctionne aussi pour les interfaces, les énumérations, toutes les dimensions des tableaux (par exemple, String[].class
), les primitives (par exemple, int.class
), et le mot-clé void
(c - void.class
).
Il est intéressant de noter, Class
lui-même est générique (déclarée Class<T>
où T
représente le type de l' Class
objet représentant), ce qui signifie que le type d' String.class
est Class<String>
.
Donc, chaque fois que vous appelez le constructeur de GenSet
, vous passez dans une classe littéral pour le premier argument représente un tableau de l' GenSet
de l'instance de type déclaré (par exemple, String[].class
pour GenSet<String>
). Notez que vous ne serez pas en mesure d'obtenir un tableau de primitives, depuis primitives ne peuvent pas être utilisés pour les variables de type.
Dans le constructeur, l'appel de la méthode cast
rendements passés Object
argument de fonte à la classe représentée par l' Class
objet sur lequel la méthode a été appelée. L'appel de la méthode statique newInstance
en java.lang.reflect.Array
retourne en tant que Object
un tableau du type représenté par l' Class
objet passé comme premier argument et de la longueur spécifiée par l' int
passé en second argument. L'appel de la méthode getComponentType
renvoie un Class
objet représentant le type de composant de la matrice représentée par l' Class
objet sur lequel la méthode a été appelée (par exemple, String.class
pour String[].class
, null
si l' Class
objet ne représente pas un tableau).
Cette dernière phrase n'est pas tout à fait exacte. Appelant String[].class.getComponentType()
renvoie un Class
objet représentant la classe - String
, mais son type est - Class<?>
, pas Class<String>
, ce qui est pourquoi vous ne pouvez pas faire quelque chose comme ce qui suit.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
En va de même pour chaque méthode en Class
qui renvoie un Class
objet.
Quant à Joachim Sauer commentaire de cette réponse (je n'ai pas assez de réputation pour commenter moi-même), l'exemple d'utilisation de la fonte d' T[]
entraînera un avertissement, car le compilateur ne peut pas garantir la sécurité de type dans ce cas.
Edit concernant les Oing commentaires:
public static <T> T[] newArray(Class<T[]> type, int size)
{
return type.cast(Array.newInstance(type.getComponentType(), size));
}