2009-12-03 10 views
15

Je voudrais utiliser une liste générique, mais la méthode d'initialisation ne renvoie qu'un List. Le code suivant fonctionne bien:Génériques et le point d'interrogation

List tmpColumnList = aMethodToInitializeTheColumnList(); 
tmpColumnList.add("ANICELITTLECOLUMN"); 

Java accuse que j'utilise un type cru et je paramerize la liste. J'ai donc ajouté le point d'interrogation paramétrer cette liste.

List<?> tmpColumnList = aMethodToInitializeTheColumnList(); 
tmpColumnList.add("ANICELITTLECOLUMN"); 

Le problème est: Maintenant, la méthode add(..) ne fonctionne plus.
Je ne peux pas assurer que la liste contient seulement String s comme aMethodToInitializeTheColumnList() n'est pas mis en œuvre dans mon code.

Quelle est mon erreur?

Merci!

+1

Comment cela a-t-il fonctionné dans le premier extrait? Missing 'new' ... – Abel

+3

Abel: Un appel de fonction initialise la liste. Je vais l'ajouter pour clarifier cette chose. – guerda

+0

Fixer la méthode d'initialisation? –

Répondre

26

À partir du didacticiel Generics. Merci à Michael's answer!

Il n'est pas sûr d'ajouter des objets arbitraires à elle cependant:

Collection<?> c = new ArrayList<String>(); 
c.add(new Object()); // Compile time error 

Puisque nous ne savons pas ce que l'élément type de c signifie, nous ne pouvons pas ajouter objets à elle . La méthode add() prend arguments de type E, le type d'élément de la collection. Lorsque le paramètre de type est?, Il signifie un type inconnu. Tout paramètre que nous passe pour ajouter devrait être un sous-type de ce type inconnu. Puisque nous ne savons pas quel type c'est, nous ne pouvons pas passer quoi que ce soit. La seule exception est null, qui est un membre de chaque type.

+4

Pardonnez mon ignorance (je ne suis pas un gars de Java). Quel est le but de l'avoir si cela ne fonctionne pas? – jww

+4

@noloader: le but est le suivant: si vous avez un paramètre de méthode de type 'Collection ', vous pouvez transmettre un 'Collection ', un 'Collection ' ou un 'Collection ', et dans la méthode vous pouvez obtenir le contenu de ces collections en tant que type 'Object'. Le fait que vous ne puissiez rien ajouter à la collection est important car cela garantit que les contraintes de type d'origine ne sont pas violées. –

17

Vous voulez probablement utiliser List<String> - c'est comme cela que les génériques sont destinés à être utilisés, c'est-à-dire ajouter des informations sur le type d'objets qui seront dans une collection. Si vous avez réellement une liste contenant des types mixtes (ce qui est généralement un signe de mauvaise conception), utilisez List<Object>

Pour plus d'informations sur l'utilisation des caractères génériques, consultez le Generics Tutorial. Mais ils ne sont vraiment pertinents que lorsque vous définissez vos propres classes génériques, ou des méthodes avec des paramètres génériques.

+0

Merci pour l'indice. Je ne peux pas garantir que cette liste contient uniquement des chaînes. – guerda

+1

Dans ce cas, vous pourriez utiliser la liste , ou peut-être quelque chose d'autre, selon ce que vous savez que la liste contiendra (par exemple Liste ) – Fortega

+0

Dans le didacticiel des génériques, voici la solution, voir ma propre réponse. Je vais envisager d'accepter votre réponse parce que vous m'avez donné l'indice. – guerda

16

Si vous utilisez <?>, vous voulez dire que vous n'allez pas utiliser le type paramétré n'importe où. Soit aller au type spécifique (dans votre cas, il semble List<String>) ou au très générique List<Object>

+0

Je ne veux pas le spécifier, mais pourquoi la méthode 'add' normale échoue-t-elle alors? – guerda

+2

Eh bien, le compilateur applique la cohérence sémantique. Vous dites que vous n'utiliserez pas le type paramétré, donc il ne vous laisse pas. La méthode 'add' attend un paramètre dont le type est le paramètre générique, donc vous n'êtes pas autorisé à l'utiliser si vous n'en spécifiez aucun. – Romain

+3

Parce que le type est * inconnu *. La compilation n'a aucune possibilité de déterminer si un 'String' serait approprié, donc vous n'êtes pas autorisé à ajouter un' String' à la liste. (En fait, vous n'êtes pas autorisé à ajouter quoi que ce soit à cette liste, excepté 'null'.) – Bombe

2

Le List<?> signifie que la liste est (ou pourrait être) tapée, mais le type est inconnu **. Donc, ajouter quelque chose pourrait être faux **, si vous êtes en dehors du type. Parce que c'est inconnu, vous êtes prévenu.

Vous pouvez utiliser List<Object>, ce qui signifie une liste pouvant contenir n'importe quel type.

+0

Je ne suis pas seulement averti, le code échoue au moment de la compilation! – guerda

+0

@furtelwart Vrai, ma formulation a été mal choisie :-). Mais le point de cette erreur de compilation est que le compilateur signale que le code est potentiellement faux. BTW, c'est le point entier du sous-système Generics tel que mis en œuvre, pour rechercher la sécurité du code à la compilation, et ajouter des lancers à l'exécution ... – KLE

+0

Pardonnez mon ignorance (je ne suis pas un gars de Java). Quel est le but de l'avoir si cela ne fonctionne pas? – jww

8

Une autre option dans ce cas serait de déclarer votre liste pour un

List<? super String> 

depuis ces modèles exactement ce que vous savez à ce sujet. Vous dites que vous ne savez pas exactement quelles sont ses limites de type, mais à partir de votre deuxième ligne, il est juste de supposer qu'il doit être capable de contenir des chaînes.

Cela compile et à mon avis, est un peu plus agréable qu'un List<Object> car il encode votre incertitude quant à ce qui peut réellement aller dans la liste. Fondamentalement, vous pouvez seulement ajouter Strings à elle, mais quand vous appelez get() l'élément retourné pourrait être n'importe quoi (et Java déduira correctement ce type à Object).

En pratique, la seule différence entre cela et List<Object> est que celui-ci permettrait tmpColumnList.add(3) ou tmpColumnList.add(new Thread()) etc. Je préfère la sémantique qu'il porte, ainsi que la pratique.