Cela ne compile pas, aucune suggestion appréciée.
...
List<Object> list = getList();
return (List<Customer>) list;
Le compilateur dit: impossible de lancer List<Object>
versList<Customer>
Cela ne compile pas, aucune suggestion appréciée.
...
List<Object> list = getList();
return (List<Customer>) list;
Le compilateur dit: impossible de lancer List<Object>
versList<Customer>
Réponses:
vous pouvez toujours convertir n'importe quel objet en n'importe quel type en le convertissant d'abord en Object. dans ton cas:
(List<Customer>)(Object)list;
vous devez être sûr qu'au moment de l'exécution, la liste ne contient que des objets Customer.
Les critiques disent qu'un tel casting indique quelque chose qui ne va pas avec votre code; vous devriez pouvoir modifier vos déclarations de type pour éviter cela. Mais les génériques Java sont trop compliqués et pas parfaits. 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 que vous savez que ce que vous essayez de faire est sûr. Dans ce cas, faites simplement le moulage brut au besoin, afin de pouvoir quitter le travail pour la maison.
@SuppressWarnings("unchecked")
. Notez que vous pouvez également effectuer une conversion ascendante vers (List)
au lieu de vers (Object)
.
En effet, bien qu'un client soit un objet, une liste de clients n'est pas une liste d'objets. Si c'était le cas, vous pourriez mettre n'importe quel objet dans une liste de clients.
.Cast<T>()
et une appelée .OfType<T>()
. Le premier effectue un cast sur chaque élément (en lançant les exceptions souhaitées) tandis que le second filtre les éléments qui ne peuvent pas être castés (vous en choisiriez donc un en fonction de votre scénario d'utilisation).
instanceof
client?
En fonction de 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.
Avec Java 8 Streams :
Parfois, le casting par 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 est que vous pouvez diffuser votre liste plus élégamment si vous ne pouvez pas être sûr de ce qu'elle contient:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
fonctionné pour moi.
Vous pouvez utiliser une double distribution.
return (List<Customer>) (List) getList();
Notez que je ne suis pas un programmeur Java, mais en .NET et C #, cette fonctionnalité est appelée 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 il n'est que bêta, donc je ne sais pas lequel des deux termes décrit votre problème, mais laissez-moi décrire le problème technique avec cela.
Supposons que vous ayez été autorisé à lancer. Notez, je dis lancer , puisque c'est ce que vous avez dit, mais il y a deux opérations qui pourraient être possibles, le casting et la conversion .
La conversion signifierait que vous obtenez un nouvel objet de liste, mais 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 ce qui suit était autorisé (note, je suppose qu'avant la distribution, la liste des objets ne contient en fait que des objets Customer, sinon la distribution 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 tenterait de traiter un objet, qui n'est pas un client, comme un client, et vous obtiendriez une erreur d'exécution à un moment donné, soit sous forme à l'intérieur de la liste, soit à partir de l'affectation.
Les génériques, cependant, sont censés vous donner des types de données sécurisés, comme des collections, et comme ils aiment jeter le mot «garanti», ce type de conversion, 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 distribution ne sera pas être autorisé. Il en va de même pour java, même si je ne suis pas sûr de l'intention d'introduire la co- et la contravariance dans le langage java.
J'espère que quelqu'un avec une meilleure connaissance de Java que moi pourra vous donner les détails pour le futur ou l'implémentation de Java.
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
Vous ne pouvez pas parce List<Object>
que vous List<Customer>
n'êtes pas dans le même arbre d'héritage.
Vous pouvez ajouter un nouveau constructeur à votre List<Customer>
classe qui prend a List<Object>
, puis itère dans la liste en convertissant chacun Object
en a Customer
et en l'ajoutant à votre collection. Sachez qu'une exception de conversion non valide peut se produire si l'appelant List<Object>
contient quelque chose qui n'est pas unCustomer
.
Le but des listes génériques est de les contraindre à certains types. Vous essayez de prendre une liste qui peut contenir n'importe quoi (commandes, produits, etc.) et de la presser dans une liste qui ne peut accepter que des clients.
Votre meilleur pari est de créer un nouveau List<Customer>
, de parcourir le List<Object>
, d'ajouter chaque élément à la nouvelle liste et de le renvoyer.
Comme d'autres l'ont souligné, vous ne pouvez pas les lancer de manière sauve, car a List<Object>
n'est pas un List<Customer>
. Ce que vous pouvez faire, c'est définir une vue sur la liste qui effectue une vérification de type sur place. En utilisant des collections Google qui seraient:
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.
}
});
Similaire avec Bozho ci-dessus. Vous pouvez faire une solution de contournement ici (bien que je ne l'aime pas moi-même) via cette méthode:
public <T> List<T> convert(List list, T t){
return list;
}
Oui. Il convertira votre liste dans le type générique demandé.
Dans le cas donné ci-dessus, vous pouvez faire du code comme celui-ci:
List<Object> list = getList();
return convert(list, new Customer());
Selon ce que vous voulez faire de la liste, vous n'aurez peut-être même pas besoin de la convertir en fichier List<Customer>
. Si vous souhaitez uniquement ajouter des Customer
objets à 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 légal, mais correct - la liste est "d'un supertype au client"), et si vous allez la transmettre à une méthode qui ajoutera simplement des objets à la liste, alors ce qui précède des bornes génériques sont suffisantes pour cela.
D'un autre côté, si vous souhaitez récupérer des objets de la liste et les faire saisir fortement en tant que clients, vous n'avez pas de chance, et à juste titre. Étant donné que la liste est une, List<Object>
il n'y a aucune garantie que le contenu soit des clients, vous devrez donc fournir votre propre casting lors de la récupération. (Ou soyez vraiment, absolument, doublement sûr que la liste ne contiendra Customers
et n'utilisera qu'un double cast de l'une des autres réponses, mais réalisez que vous contournez complètement la sécurité de type au moment de la compilation que 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, doublement si elle doit être utilisée comme méthode de bibliothèque. Si vous ne lisez qu'à partir d'une liste, utilisez List<? extends T>
au lieu de List<T>
, par exemple - cela donne à vos appelants beaucoup plus de possibilités dans les arguments qu'ils peuvent transmettre et signifie qu'ils sont moins susceptibles de rencontrer des problèmes évitables similaires à celui que vous '' re avoir ici.