2009-07-24 8 views
2

Dire que j'ai cette classe:Comment jeter une liste complète sans itérer en Java

public class BaseJob{ 

String name; 

public void setName(String name){ 
this.name=name; 
} 
public String getName() 
{ 
    return name; 
} 
} 

et une autre classe qui la prolonge:

public class DetailedJob extends BaseJob{ 

public void doThing(); 

} 

De plus, j'ai cette méthode dans un autre classe:

List<BaseJob> getSomeJobs() 

maintenant, mon problème est:

est-il possible d'éviter de lancer chaque élément de manière séquentielle dans la liste retournée de getSomeJobs, si je sais avec certitude que chaque BaseJob retourné est en effet un DetailedJob?

Autrement dit, est-il une autre solution que ce qui suit pour jeter tous les éléments dans la liste:

List<BaseJob> baseJobList = getSomeJobs(); 
List<DetailedJob> detailedJobList = new ArrayList<DetailedJob>(); 
for (BaseJob baseJob : baseJobList) 
    detailedJobList.add((DetailedJob) baseJob); 

Répondre

2

Eh bien, il y a:

List<BaseJob> baseJobList = getSomeJobs(); 
@SuppressWarnings("unchecked") 
List<DetailedJob> detailedJobList = (List) baseJobList; 

L'inconvénient est que si l'un des emplois dans la liste ne sont pas des emplois détaillés, l'exception ne sera levée lorsque quelqu'un essaie de le chercher. En outre, si un nouveau travail non détaillé est ajouté à baseJobList par la suite, cela pourrait bousiller n'importe qui en utilisant detailedJobList. Fondamentalement, vous avez perdu beaucoup de sécurité de type. Dans certains cas, vous ne pouvez pas vous en soucier, mais ce n'est pas quelque chose que vous devriez faire à la légère.

+1

je tenté de donner cette réponse, mais c'est vraiment dangereux, comme vous l'avez noté correctement – dfa

+2

Le casting devrait être de '(liste)' 'non (Liste )'. Sinon, il ne compilera pas. – notnoop

+0

Vous avez généralement besoin d'un double plâtre pour les lancers impossibles. –

0

Vous pouvez créer une méthode getSomeJobs paramétrés pour prendre un argument en disant que vous savez tout est DetailedJob, ce qui signifie qu'il renvoie une liste DetailedJob plutôt que la classe de base.

Si vous utilisez instanceof, vous n'auriez même pas besoin de lancer, vous pourriez simplement demander si chaque élément est une instance d'un DetailedJob et continuer là. Ce n'est presque pas mieux que de boucler chaque objet et lancer, cependant.

0

Faire getSomeJobs() ou écrire une autre fonction getSomeDetailedJobs() qui retourne Liste < DetailedJob> au lieu de la liste < BaseJob>. Je ne sais pas comment nous pouvons être "sûrs" de tous les éléments étant de type DetailedJobs.

+0

... jusqu'à ce que j'ai vu la réponse de Jon Skeet! – Sathya

+0

"retourne Liste au lieu de Liste" <- intéressant ... – geowa4

+0

oups désolé corrigé. – Sathya

5

Si vous savez que tous les jobs vont être des jobs détaillés, pourquoi les mettriez-vous dans un arraylist de basejobs? Il n'y a pas de raison de le faire, et cette méthode éliminerait beaucoup d'erreurs et d'exceptions possibles.

+0

Parce que la classe holding getSomeJobs fonctionne uniquement avec BaseJob et ne veut pas savoir si ces baseJobs sont des detailedJobs ou autre chose. – madewulf

+0

Mais ce sont des basejobs, et ils peuvent être utilisés pour tout ce que peut faire un job de base. –

8

Probablement ce que vous voulez faire est de paramétrer la classe qui définit getSomeJobs.

public final class JobHolder<T extends BaseJob> { 
    public List<T> getSomeJobs() { 
     ... 

Les dominantes généralement non vérifiées indiquent un problème de conception. Ils sont inévitables dans certaines situations, telles que les implémentations de bas niveau et la sérialisation.

+0

Cela semble être une bonne solution. Malheureusement, je ne suis pas autorisé à changer le code de JobHolder, comme vous l'avez nommé, – madewulf

+0

Cela sera utilisé comme: JobHolder jobHolder = new JobHolder (); Liste emplois = jobHolder.getSomeJobs(); – Mnementh

0

Bien qu'il ne résout pas directement votre problème de casting, je serais temped d'utiliser deux méthodes sur la « autre classe »:

List<BaseJob> getAllJobs(); 

et

List<DetailedJob> getDetailedJobs(); 

Cela rend votre code plus lisibles à tous ceux qui utilisent «l'autre classe» et éviteront les erreurs. Soit cela ou je générique l'autre classe comme @Tom Hawtin suggère.

0

Votre autre classe qui fournit la méthode getSomeJobs devrait implémenter une interface (pour aider avec vos tests unitaires, entre autres choses). Appelons-le JobProvider. Vous pouvez déclarer l'interface de sorte qu'elle produise toujours une liste de quelque chose qui étend un travail de base, et dans les sous-classes où vous savez que votre travail sera toujours d'un certain sous-type, vous pouvez restreindre la définition de type là.

interface JobProvider { 
    List<? extends BaseJob> getSomeJobs(); 
} 

class JobProviderImpl implements JobProvider { 
    public List<DetailedJob> getSomeJobs() { 
     // do stuff and return 
    } 
} 

Maintenant, dans un autre code, si vous savez que vous avez affaire à un JobProviderImpl, vous pouvez le cas où il et savoir que la liste ne contient que DetailedJob s.

if (provider instanceof JobProviderImpl) { 
    List<DetailedJob> detailedJobs = ((JobProviderImpl) provider).getSomeJobs(); 
} 
Questions connexes