47 votes

Comment utiliser des génériques avec un tableau de classes?

Je veux créer un tableau de Classes, représentant chacune un type qui est disponible dans le système que je suis en train de construire. Toutes les Classes sont des sous-classes d'une commune de la super-classe. Donc je voudrais faire:

Class<? extends SuperClass>[] availableTypes = { SubClass1.class, SubClass2.class };

Cela me donne l'erreur:

Cannot create a generic array of Class<? extends SuperClass>.

Je reçois le même message si je tente de qualifier la création de la table sur le côté droit de l'initialisation:

Class<? extends SuperClass>[] availableTypes = Class<? extends SuperClass>[] { SubClass1.class, SubClass2.class };

Je peux obtenir le code à compiler si j'élimine médicaments génériques, les qualifications:

Class[] availableTypes = { SubClass1.class, SubClass2.class };

Mais puis-je obtenir les génériques d'avertissement:

La classe est une crue de type. Références de type générique de la Classe doit être paramétrée.

Je suis en train; j'essaie! :) Aussi, à ce stade, même si cela n'a pas de provoquer un avertissement, je perds un morceau de l'interface j'ai essayé de définir. Je ne tiens pas à retourner un tableau de l'arbitraire des classes; je veux retourner un tableau de classes qui sont toutes les sous-classes d'une classe mère!

Eclipse a un assez puissants outils pour comprendre quels sont les paramètres à utiliser pour résoudre les génériques des déclarations, mais dans ce cas, il tombe, car il tend à faire quand vous avez affaire avec Classe. Le "Déduire de Type Générique" Arguments de la procédure qu'il propose ne permet pas de modifier le code à tous, en laissant l'avertissement.

J'ai été en mesure de contourner ce problème en utilisant une Collection à la place:

List<Class<? extends SuperClass>> availableTypes = new List<Class<? extends SuperClass>>();

Mais quelle est la bonne façon de le faire avec des tableaux?

23voto

Simon Nickerson Points 17147

Il semble un peu défaitiste, mais des problèmes de ce genre sont précisément la raison pour laquelle la plupart des gens d'éviter de mélanger les tableaux et les génériques. En raison de la façon dont les génériques sont mis en œuvre (type d'effacement), les tableaux et les génériques ne fonctionnera jamais bien ensemble.

Deux solutions:

  • Coller à l'aide d'une collection (par exemple, ArrayList<Class<? extends SuperClass>>), qui fonctionne aussi bien comme un tableau et permet également à l'expansion.
  • Mettre un @SuppressWarnings("unchecked") annotation sur le code de la création du tableau avec un commentaire justifiant son utilisation.

14voto

erickson Points 127945

Utilisez cette syntaxe:

 Class<? extends SuperClass>[] avail = new Class[] { SubClass1.class, ... };
 

Cela vous donnera un avertissement "non vérifié", et à juste titre, car vous pourriez inclure un objet Class pour un type qui ne s'étend pas de SuperClass dans le tableau.

12voto

Eddie Points 27755

La bonne façon de le faire avec des tableaux est de le faire avec une Collection. Désolé! Pour un ensemble complexe de raisons, les tableaux ne pas jouer gentil avec les génériques. Les tableaux ont un autre modèle de covariance que des objets génériques, ce qui provoque finalement les problèmes que vous rencontrez. Par exemple, avec les tableaux, mais pas (normalement) avec des objets génériques, vous pouvez faire légalement ce:

Object[] myArray = new String[5];

si vous ne pouvez pas faire cela:

LinkedList<Object> myCollection = new LinkedList<String>();

Si vous voulez plus de détails, vous pouvez voir les Tableaux En Java Génériques page de l'excellent Génériques FAQ

Comme simonn dit, vous pouvez aussi utiliser vos tableaux comme ils sont, et d'utiliser @SuppressWarnings("unchecked") pour réduire au silence les avertissements. Cela fonctionnera, mais sans le type de sécurité que les génériques peut vous fournir. Si c'est la performance que vous êtes inquiet, il suffit d'utiliser un ArrayList si vous êtes juste en utilisant un mince wrapper autour d'un tableau, mais avec tous les type de garanties de sécurité prévues par les génériques.

5voto

John Feminella Points 116878

Mais quelle est la bonne façon de le faire avec des tableaux?

Il n'y a pas de type moyen sûr de le faire; à l'aide de la collection est la bonne approche. Pour comprendre pourquoi, imaginez si c'était autorisé. Vous pourriez avoir une situation comme celle-ci:

// Illegal!
Object[] baskets = new FruitBasket<? extends Citrus>[10];

// This is okay.
baskets[0] = new FruitBasket<Lemon>();

// Danger! This should fail, but the type system will let it through.
baskets[0] = new FruitBasket<Potato>();

Le type de système doit détecter si un panier qui est ajouté à la matrice est de type FruitBasket<? extends Citrus> ou un sous-type. Un FruitBasket ne correspond pas et doit être rejetée avec un ArrayStoreException. Mais rien ne se passe!

En raison du type d'effacement, la JVM ne peut voir le moteur d'exécution type de la matrice. Au moment de l'exécution, nous avons besoin de comparer le type de tableau pour le type d'élément pour vous assurer qu'ils correspondent. Le tableau d'exécution du composant est de type FruitBasket[] après le type d'effacement; de même, l'élément moteur d'exécution est de type FruitBasket. Pas de problèmes seront détectés -- et c'est pourquoi c'est dangereux.

2voto

Michael Myers Points 82361

Le problème est qu'il est illégal de créer un tableau d'un type générique. La seule façon de contourner cela est de casting pour le type générique lorsque vous créez le tableau, mais ce n'est pas une très bonne solution. (Notez qu'il est possible d' utiliser un générique du tableau, juste de ne pas en créer un: voir à cette question.)

Vous devriez presque toujours à l'aide de listes au lieu de tableaux, de toute façon, je pense donc que vous est venu avec la meilleure solution déjà.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X