2010-03-19 5 views
12

Est-il possible (ou même conseillé) de lancer l'élément extrait d'une instruction for each dans l'instruction elle-même? Je sais que chaque élément de la liste sera de type <SubType>.Elément cast en Java pour chaque instruction

i.e. .:

List<BaseType> list = DAO.getList(); 
for(<SubType> element : list){ 
    // Cannot convert from element type <BaseType> to <SubType> 
    ... 
} 

plutôt que:

List <BaseType> list = DAO.getList(); 
for(<BaseType> el : list){ 
    <SubType> element = (<SubType>)el; 
    ... 
} 

Répondre

12

-vous vraiment savent que chaque entrée va être un sous-type? Le DAO doit simplement remplir le contrat List<BaseType>, et si vous supposez une sous-classe, alors je pense que quelque chose ne va pas quelque part. Je me concentrerais peut-être plus sur la correction de l'interface avec le DAO, et je lui retournerais ce que vous voulez.

+0

+1 pour indiquer de manière si éloquente le mécanisme de contrat auquel les interfaces doivent adhérer. – aperkins

+1

Malheureusement, le code DAO n'est pas le nôtre. Cependant, les flux dans la source de données sont. Nous avons sous-classé (la seule de ces sous-classes) puisque nous voulions des fonctionnalités supplémentaires dans la classe. Puisque nous contrôlons l'entrée et que nous y mettons uniquement des objets , je pense que je peux être assez certain que l'objet récupéré sera effectivement l'un des . Si nous contrôlions tout le code, vous seriez 100% correct. –

+3

@Carl - Cela vaut-il la peine d'envelopper le DAO, et de fournir une interface * différente * qui fait ce que vous voulez. Sinon, vous devrez convertir tout le contenu de votre base de code (potentiellement - je me rends compte que je fais des hypothèses sur la façon dont cette distribution est largement répandue) –

1

Possible, oui! mais que Dieu m'en garde, pourquoi? Mes premières tentatives dans ma carrière l'ont fait et j'ai appris. La programmation aux interfaces a toujours un avantage. Je reçois toujours des questions de développeurs juniors sur la gestion des cas où seuls les sous-types ont les méthodes/fonctionnalités requises.

Dire la classe Animal avec un sous-type Dog ayant la méthode bark(). Ils veulent la fonctionnalité bark(). Le vrai défi est qu'ils veulent un comportement de communication animale pas aboyer() mais animal parler(). Donc, une nouvelle sous-classe Cat ne nécessiterait pas de meow(). Qu'en est-il alors: - Mon chien forme une meute, mais pas les chats. Le comportement de answer pack() n'appartient pas à un seul chien. Pack est un aspect différent, passez un pack à tous les objets et demandez aux objets de rejoindre le pack. (Modèle de visiteur/modèle d'adaptateur). Ma classe Wolf peut utiliser le même comportement.

Suis-je rigide à ce sujet, non si ce n'est que 1 éteint par exemple, je vais bien. Si la réponse est je ne suis pas sûr, alors vous feriez mieux de jouer en toute sécurité en travaillant à des contrats d'interface.

12

Pour toutes les raisons indiquées par d'autres, vous ne devriez pas faire cela. Toutefois, si vous ne pouvez pas changer l'interface, ce qui suit est possible:

for (BaseType element : list) { 
    SubType subType = (SubType)element; 
    ... 
} 

Pour autant que je sache, c'est la seule façon de le faire et rester de type vraiment sûr - c.-à-pas compter sur l'effacement de type pour attraper tout problèmes, ce qu'il ne fera pas nécessairement beaucoup plus tard. Je réalise que ce n'est pas exactement ce que vous cherchiez, mais il gère la coulée.

+0

Je devrais noter, que si vous pouvez changer l'interface, et ce sera TOUJOURS le sous-type, vous DEVRIEZ changer l'interface, que ce soit à travers une extension de sous-classe ou juste le changer. – aperkins

+2

Pour être vraiment sûr, vous pouvez faire: if (element instanceof SubType) – VolatileDream

+0

Très vrai - j'aurais dû mettre cela. – aperkins

0

Si vous n'êtes pas intéressé par les collections Google, vous pouvez envelopper la liste avec la méthode transform. Dans votre cas, il sera très efficace et totalement conforme. Je voudrais le mettre comme une méthode d'emballage bien que Brian a suggéré.

public List<SubType> fromDao () 
{ 
    // Put a comment for maintainer 

    // Lists from DAO always contain SubTypes 
    return 
     Lists.transform(
      DAO.getList(), 
      new Function< BaseType, SubType >() 
      { 
       public SubType apply (final BaseType from) 
       { 
        return (SybType) from; 
       } 
      }; 
} 
9

Il est en effet possible de combiner la distribution avec la boucle, comme ceci:

List<BaseType> list = DAO.getList(); 
for (SubType subType : ((List<SubType>) list)){ 
    ... 
} 

Ou vous pouvez utiliser ce modèle légèrement plus propre:

List<SubType> list = (List<SubType>) DAO.getList(); 
for (SubType subType : list){ 
    ... 
} 

Vous allez obtenir un avertissement cast non compilé à partir du compilateur Java, sauf si vous le supprimez. L'effet de la première forme sera effectivement identique à la coulée de chaque élément dans la boucle. Le second formulaire appliquera également que les nouveaux ajouts à la liste doivent être conformes à SubType.Notez que cela ne fonctionnera PAS avec les tableaux, car les tableaux ont des types d'exécution distincts. En d'autres termes, BaseType [] n'est pas convertible en SubType []. Vous pouvez utiliser l'API Arrays pour contourner ce problème, comme suit:

BaseType[] array = DAO.getArray(); 
for (SubType subType : Arrays.<SubType>asList(array)) { 
    ... 
} 
+0

Ces moulages ne sont pas légaux, bien que vous pouvez faire [quelques astuces] (https://stackoverflow.com/questions/933447/how-do-you-cast-a-list-of-objects-from-one-type- to-another-in-java) pour contourner ce problème (comme une distribution intermédiaire vers 'List '.) Le [tutoriel java] (https://docs.oracle.com/javase/tutorial/java/generics/subtyping. html) lié à partir de cette question note: "Bien que Integer soit un sous-type de Number, la liste n'est pas un sous-type de la liste et, en fait, ces deux types ne sont pas liés Le parent commun de List et List est Liste " –

+0

Le deuxième exemple fonctionnera si DAO.getList renvoie une liste non typée plutôt que la liste . Le modèle peut être utile lorsqu'il s'agit d'une base de code héritée dans laquelle aucune collection n'est typée. – harperska