web-dev-qa-db-fra.com

Comment lancer List <Object> en List <MyClass>

Cela ne compile pas, aucune suggestion appréciée.

 ...
  List<Object> list = getList();
  return (List<Customer>) list;

Le compilateur dit: ne peut pas lancer List<Object> à List<Customer>

86
user198313

vous pouvez toujours convertir n'importe quel objet en n'importe quel type en le convertissant d'abord en objet. dans ton cas:

(List<Customer>)(Object)list; 

vous devez vous assurer qu'au moment de l'exécution la liste ne contient que des objets Client.

Les critiques disent qu'un tel casting indique un problème avec votre code; vous devriez pouvoir modifier vos déclarations de type pour l’éviter. Mais Java les génériques sont trop compliqués, et ce n’est pas parfait. Parfois, vous ne savez tout simplement pas s’il existe une jolie solution pour satisfaire le compilateur, même si vous connaissez très bien les types d’exécution et vous savez que ce que vous essayez de faire est sûr. Dans ce cas, effectuez le moulage brut si nécessaire pour pouvoir quitter le travail et rentrer chez vous.

140
irreputable

En effet, bien qu'un client soit un objet, une liste de clients ne soit pas un liste d'objets. Si c'était le cas, vous pourriez alors mettre n'importe quel objet dans une liste de clients.

36
Brian Agnew

Selon votre autre code, la meilleure réponse peut varier. Essayer:

List<? extends Object> list = getList();
return (List<Customer>) list;

ou

List list = getList();
return (List<Customer>) list;

Mais gardez à l'esprit qu'il n'est pas recommandé de faire de tels lancers non contrôlés.

32
Bozho

Vous pouvez utiliser une distribution double.

return (List<Customer>) (List) getList();
21
Peter Lawrey

Avec Java 8 Flux) :

Parfois, le lancer de la force brute convient:

List<MyClass> mythings = (List<MyClass>) (Object) objects

Mais voici une solution plus polyvalente:

List<Object> objects = Arrays.asList("String1", "String2");

List<String> strings = objects.stream()
                       .map(element->(String) element)
                       .collect(Collectors.toList());

Il y a une tonne d'avantages, mais l'un d'entre eux est que vous pouvez utiliser votre liste de manière plus élégante si vous ne savez pas exactement ce qu'elle contient:

objects.stream()
    .filter(element->element instanceof String)
    .map(element->(String)element)
    .collect(Collectors.toList());
16
roundar

Notez que je ne suis pas un programmeur Java, mais en .NET et C #, cette fonctionnalité s’appelle contravariance ou covariance. Je n’ai pas encore approfondi ces choses, car elles sont nouvelles dans .NET 4.0 , que je n’utilise pas car c’est seulement de la bêta, alors je ne sais pas lequel des deux termes décrit votre problème, mais laissez-moi décrire le problème technique que cela pose.

Supposons que vous avez été autorisé à lancer. Notez, je dis cast, puisque c'est ce que vous avez dit, mais il y a deux opérations qui pourraient être possibles, casting et convertir.

La conversion signifie que vous obtenez un nouvel objet de liste, mais que vous dites casting, ce qui signifie que vous souhaitez traiter temporairement un objet comme un autre type.

Voici le problème avec ça.

Que se passerait-il si les éléments suivants étaient autorisés (note, je suppose qu'avant la conversion, la liste des objets ne contient en réalité que des objets Client, sinon la conversion ne fonctionnerait pas, même dans cette version hypothétique de Java):

List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];

Dans ce cas, cela essaierait de traiter un objet qui n'est pas un client, et vous obtiendrez une erreur d'exécution à un moment donné, que ce soit dans la liste ou à partir de l'affectation.

Les génériques, cependant, sont supposés vous donner des types de données sécurisés, tels que des collections, et comme ils aiment jeter le mot "garanti", ce type de distribution, avec les problèmes qui suivent, n'est pas autorisé.

Dans .NET 4.0 (je sais, votre question portait sur Java), cela sera autorisé dans certains cas très spécifiques, où le compilateur peut garantir que les opérations que vous effectuez sont sûres, mais dans le sens général , ce type de casting ne sera pas autorisé. Il en va de même pour Java, bien que je ne sois pas sûr de l’intention d’introduire des co- et contravariances dans le langage Java.

Si tout va bien, quelqu'un avec une meilleure connaissance de Java que moi) peut vous donner les détails de l'avenir ou de la mise en œuvre de Java.

Une autre approche consisterait à utiliser un flux Java 8.

    List<Customer> customer = myObjects.stream()
                                  .filter(Customer.class::isInstance)
                                  .map(Customer.class::cast)
                                  .collect(toList());
3
d0x

Vous devriez simplement parcourir la liste et lancer tous les objets un par un

3
vrm

Vous pouvez faire quelque chose comme ça

List<Customer> cusList = new ArrayList<Customer>();

for(Object o: list){        
    cusList.add((Customer)o);        
}

return cusList; 

Ou le Java 8 façons

list.stream().forEach(x->cusList.add((Customer)x))

return cuslist;
3
Malkeith Singh

Vous ne pouvez pas parce que List<Object> et List<Customer> ne sont pas dans le même arbre d'héritage.

Vous pouvez ajouter un nouveau constructeur à votre List<Customer> classe qui prend un List<Object> puis parcourez la liste en transformant chaque Object en un Customer et en l’ajoutant à votre collection. Sachez qu'une exception de diffusion invalide peut survenir si le List<Object> contient quelque chose qui n'est pas un Customer.

Le but des listes génériques est de les contraindre à certains types. Vous essayez de prendre une liste pouvant contenir n'importe quoi (commandes, produits, etc.) et de l'insérer dans une liste ne pouvant contenir que des clients.

2
Rob Sobers

Selon ce que vous voulez faire avec la liste, il se peut que vous n’ayez même pas besoin de la convertir en un List<Customer>. Si vous souhaitez uniquement ajouter des objets Customer à la liste, vous pouvez le déclarer comme suit:

...
List<Object> list = getList();
return (List<? super Customer>) list;

C’est légal (enfin, pas seulement juridique, mais correct - la liste est de "certains sur-types au client"), et si vous allez la transmettre à une méthode qui sera simplement ajoutée objets à la liste alors les limites génériques ci-dessus sont suffisantes pour cela.

D'autre part, si vous souhaitez extraire des objets de la liste et les avoir fortement typés en tant que clients, vous n'avez pas de chance, et à juste titre. Parce que la liste est un List<Object> il n'y a aucune garantie que le contenu soit client, vous devrez donc fournir votre propre casting lors de la récupération. (Ou être vraiment, absolument, doublement sûr que la liste ne contiendra que Customers et utilisera une distribution double de l'une des autres réponses, mais réalisez que vous contournez complètement la sécurité du type à la compilation vous obtenez des génériques dans ce cas).

D'une manière générale, il est toujours bon de considérer les limites génériques les plus larges possibles qui seraient acceptables lors de l'écriture d'une méthode, d'autant plus si elle doit être utilisée comme méthode de bibliothèque. Si vous ne faites que lire dans une liste, utilisez List<? extends T> au lieu de List<T> _, par exemple - cela donne à vos appelants beaucoup une plus grande portée dans les arguments qu'ils peuvent transmettre et signifie qu'ils sont moins susceptibles de se heurter à des problèmes évitables similaires à celui que vous avez ici.

1
Andrzej Doyle

Vous pouvez créer une nouvelle liste et y ajouter les éléments:

Par exemple:

List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);
1
ayushgp

Votre meilleur pari est de créer un nouveau List<Customer>, itère à travers le List<Object>, ajoutez chaque élément à la nouvelle liste et renvoyez-le.

1
Aric TenEyck

Comme d'autres l'ont fait remarquer, vous ne pouvez pas les lancer sans crainte, car un List<Object> n'est pas un List<Customer>. Ce que vous pouvez faire est de définir une vue sur la liste qui effectue une vérification de type sur place. En utilisant Google Collections , ce serait:

return Lists.transform(list, new Function<Object, Customer>() {
  public Customer apply(Object from) {
    if (from instanceof Customer) {
      return (Customer)from;
    }
    return null; // or throw an exception, or do something else that makes sense.
  }
});
1
nd.

Similaire avec Bozho ci-dessus. Vous pouvez faire quelques solutions ici (bien que je ne l’aime pas moi-même) avec cette méthode:

public <T> List<T> convert(List list, T t){
    return list;
}

Oui. Il jettera votre liste dans le type générique demandé.

Dans le cas ci-dessus, vous pouvez créer du code comme celui-ci:

    List<Object> list = getList();
    return convert(list, new Customer());
0
Hendra Jaya