157 votes

Le moyen le plus efficace de convertir une liste de sous-classes en une liste de classes de base.

J'ai un List<SubClass> que je veux traiter comme un List<BaseClass> . Il semble que cela ne devrait pas être un problème puisque le fait de lancer un SubClass à un BaseClass est un jeu d'enfant, mais mon compilateur se plaint que le cast est impossible.

Alors, quelle est la meilleure façon d'obtenir une référence aux mêmes objets qu'une List<BaseClass> ?

Pour l'instant, je fais juste une nouvelle liste et je copie l'ancienne :

List<BaseClass> convertedList = new ArrayList<BaseClass>(listOfSubClass)

Mais si je comprends bien, il faut créer une liste entièrement nouvelle. J'aimerais avoir une référence à la liste originale, si possible !

3 votes

La réponse que vous avez ici : stackoverflow.com/questions/662508/

2voto

Mike Nakis Points 7259

Ce que vous essayez de faire est très utile et je trouve que je dois le faire très souvent dans le code que j'écris. Un exemple de cas d'utilisation :

Disons que nous avons une interface Foo et nous avons un zorking qui a un ZorkingFooManager qui crée et gère les instances des paquets-privés ZorkingFoo implements Foo . (Un scénario très courant).

Donc, ZorkingFooManager doit contenir un private Collection<ZorkingFoo> zorkingFoos mais il doit exposer un public Collection<Foo> getAllFoos() .

La plupart des programmeurs Java n'y réfléchiraient pas à deux fois avant de mettre en place getAllFoos() comme l'attribution d'une nouvelle ArrayList<Foo> en le remplissant avec tous les éléments de zorkingFoos et de le renvoyer. Je me plais à penser qu'environ 30 % de tous les cycles d'horloge consommés par le code Java tournant sur des millions de machines sur toute la planète ne font rien d'autre que de créer ces copies inutiles de ArrayLists qui sont récupérées quelques microsecondes après leur création.

La solution à ce problème est, bien sûr, de réduire la collection. Voici la meilleure façon de le faire :

static <T,U extends T> List<T> downCastList( List<U> list )
{
    return castList( list );
}

Ce qui nous amène à la castList() fonction :

static <T,E> List<T> castList( List<E> list )
{
    @SuppressWarnings( "unchecked" )
    List<T> result = (List<T>)list;
    return result;
}

L'intermédiaire result est nécessaire en raison d'une perversion du langage java :

  • return (List<T>)list; produit une exception "unchecked cast" ; jusque là tout va bien ; mais ensuite :

  • @SuppressWarnings( "unchecked" ) return (List<T>)list; est une utilisation illégale de l'annotation suppress-warnings.

Donc, même si ce n'est pas kasher d'utiliser @SuppressWarnings sur un return mais il est apparemment possible de l'utiliser dans une affectation, donc la variable supplémentaire "result" résout ce problème. (De toute façon, elle devrait être éliminée par optimisation soit par le compilateur, soit par le JIT).

1voto

drordk Points 36

Et si on faisait un casting de tous les éléments. Cela créera une nouvelle liste, mais fera référence aux objets originaux de l'ancienne liste.

List<BaseClass> convertedList = listOfSubClass.map(x -> (BaseClass)x).collect(Collectors.toList());

1voto

jtahlborn Points 32515

List<BaseClass> convertedList = Collections.checkedList(listOfSubClass, BaseClass.class)

5 votes

Cela ne devrait pas fonctionner, car pour cette méthode, tous les arguments et le résultat prennent le même paramètre de type.

0 votes

Bizarre, vous avez raison. Pour une raison quelconque, j'avais l'impression que cette méthode était utile pour l'upcasting d'une collection générique. elle peut toujours être utilisée de cette façon et elle fournira une collection "sûre" si vous voulez utiliser suppresswarnings.

-2voto

olivervbk Points 283

Quelque chose comme ça devrait fonctionner aussi :

public static <T> List<T> convertListWithExtendableClasses(
    final List< ? extends T> originalList,
    final Class<T> clazz )
{
    final List<T> newList = new ArrayList<>();
    for ( final T item : originalList )
    {
        newList.add( item );
    }// for
    return newList;
}

Je ne sais pas vraiment pourquoi clazz est nécessaire dans Eclipse

-2voto

kanaparthikiran Points 91

Voici le morceau de code complet qui utilise les génériques pour convertir la liste des sous-classes en classe supérieure.

Méthode de l'appelant qui transmet le type de sous-classe

List<SubClass> subClassParam = new ArrayList<>();    
getElementDefinitionStatuses(subClassParam);

Méthode du destinataire qui accepte tout sous-type de la classe de base.

private static List<String> getElementDefinitionStatuses(List<? extends 
    BaseClass> baseClassVariableName) {
     return allElementStatuses;
    }
}

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