Pregunta Cómo convertir Lista en List

Esto no compila, cualquier sugerencia apreciada.

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

El compilador dice: no puede lanzar List<Object> a List<Customer>


75
2017-12-16 21:23


origen


Respuestas:


siempre puedes lanzar cualquier objeto a cualquier tipo mediante su conversión ascendente a Objeto primero. en tu caso:

(List<Customer>)(Object)list; 

debe estar seguro de que, en tiempo de ejecución, la lista no contiene más que objetos del Cliente.

Los críticos dicen que ese casting indica algo mal con tu código; deberías poder modificar tus declaraciones de tipo para evitarlo. Pero los genéricos de Java son demasiado complicados, y no son perfectos. A veces simplemente no se sabe si hay una solución bonita para satisfacer al compilador, a pesar de que usted conoce muy bien los tipos de tiempo de ejecución y sabe que lo que está tratando de hacer es seguro. En ese caso, solo haga la fundición de crudo según sea necesario, para que pueda dejar el trabajo para el hogar.


111
2017-12-17 10:42



Eso es porque aunque un cliente es un Objeto, una lista de clientes no es un Lista de objetos Si fuera así, entonces podrías poner alguna objeto en una lista de Clientes.


34
2017-12-16 21:25



Dependiendo de tu otro código, la mejor respuesta puede variar. Tratar:

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

o

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

Pero tenga en cuenta que no se recomienda hacer tales lanzamientos sin marcar.


28
2017-12-16 21:28



Puedes usar un doble elenco.

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

19
2017-12-18 18:18



Con Java 8 Corrientes:

A veces, la fundición de fuerza bruta está bien:

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

Pero aquí hay una solución más versátil:

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

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

Hay un montón de beneficios, pero uno es que puedes lanzar tu lista de forma más elegante si no puedes estar seguro de lo que contiene:

list.stream()
    .filter(element->element instanceof String)
    .map(element->(String)element)
    .collect(Collectors.toList());

11
2017-07-19 19:27



Tenga en cuenta que no soy un programador de Java, pero en .NET y C #, esta característica se llama contravarianza o covarianza. Todavía no me he adentrado en esas cosas, ya que son nuevas en .NET 4.0, que no estoy usando porque es solo beta, así que no sé cuál de los dos términos describe tu problema, pero déjame describir el problema técnico con esto.

Supongamos que se te permitió lanzar. Nota, digo emitir, ya que eso es lo que dijiste, pero hay dos operaciones que podrían ser posibles, fundición y mudado.

Conversión significaría que obtienes un nuevo objeto de lista, pero dices conversión, lo que significa que quieres tratar temporalmente un objeto como otro tipo.

Aquí está el problema con eso.

Qué pasaría si se permitiera lo siguiente (nota, supongo que antes del elenco, la lista de objetos en realidad solo contiene objetos de Cliente, de lo contrario el molde no funcionaría incluso en esta versión hipotética de Java):

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

En este caso, esto intentaría tratar a un objeto, que no es un cliente, como cliente, y obtendría un error de tiempo de ejecución en un punto, ya sea dentro de la lista o desde la tarea.

Sin embargo, se supone que los genéricos le brindan tipos de datos seguros para el tipo, como colecciones, y dado que les gusta arrojar la palabra 'garantizado', este tipo de molde, con los problemas que siguen, no está permitido.

En .NET 4.0 (lo sé, tu pregunta fue sobre Java), esto será permitido en algunos casos muy específicos, donde el compilador puede garantizar que las operaciones que realiza son seguras, pero en el sentido general, este tipo de molde no estará permitido. Lo mismo vale para Java, aunque no estoy seguro de ningún plan para introducir co y contravariancia en el lenguaje Java.

Con suerte, alguien con mejor conocimiento de Java que yo puede decirle los detalles para el futuro de Java o la implementación.


8
2017-12-16 21:28



Debería iterar sobre la lista y lanzar todos los objetos uno a uno


3
2017-12-16 21:27



No puedes porque List<Object> y List<Customer> no están en el mismo árbol de herencia.

Puede agregar un nuevo constructor a su List<Customer> clase que toma una List<Object> y luego iterar a través de la lista lanzando cada Object a un Customer y agregarlo a tu colección. Tenga en cuenta que puede producirse una excepción de conversión no válida si la persona que llama List<Object> contiene algo que no es un Customer.

El objetivo de las listas genéricas es restringirlas a ciertos tipos. Está tratando de tomar una lista que puede tener cualquier cosa en él (Pedidos, Productos, etc.) y exprímalo en una lista que solo puede tomar Clientes.


2
2017-12-16 21:36



Tu mejor apuesta es crear un nuevo List<Customer>, iterar a través de List<Object>, agrega cada elemento a la nueva lista y devuelve eso.


1
2017-12-16 21:27



Como han señalado otros, no puedes lanzarlos salvablemente, ya que List<Object> no es un List<Customer>. Lo que podría hacer es definir una vista en la lista que haga una verificación de tipo in situ. Utilizando Colecciones de Google eso sería:

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
2017-12-17 10:57