Isso não compila, qualquer sugestão apreciada.
...
List<Object> list = getList();
return (List<Customer>) list;
O compilador diz: não é possível lançar List<Object>
paraList<Customer>
Isso não compila, qualquer sugestão apreciada.
...
List<Object> list = getList();
return (List<Customer>) list;
O compilador diz: não é possível lançar List<Object>
paraList<Customer>
Respostas:
você sempre pode converter qualquer objeto para qualquer tipo, fazendo o up-casting para o objeto primeiro. no seu caso:
(List<Customer>)(Object)list;
você deve ter certeza de que, em tempo de execução, a lista não contém nada além de objetos Cliente.
Os críticos dizem que tal elenco indica algo errado com seu código; você deve ser capaz de ajustar suas declarações de tipo para evitá-lo. Mas os genéricos Java são muito complicados e não são perfeitos. Às vezes, você simplesmente não sabe se existe uma solução bonita para satisfazer o compilador, embora conheça muito bem os tipos de tempo de execução e saiba que o que está tentando fazer é seguro. Nesse caso, basta fazer a fundição bruta conforme necessário, para que você possa sair do trabalho e voltar para casa.
@SuppressWarnings("unchecked")
. Observe que você também pode fazer upcast para em (List)
vez de para (Object)
.
Isso porque, embora um cliente seja um objeto, uma lista de clientes não é uma lista de objetos. Se fosse, você poderia colocar qualquer objeto em uma lista de Clientes.
.Cast<T>()
e outro chamado .OfType<T>()
. O primeiro executa uma conversão em cada elemento (lançando as exceções desejadas), enquanto o último filtra os elementos que não podem ser lançados (então você escolheria um dependendo do seu cenário de uso).
instanceof
cliente?
Dependendo do seu outro código, a melhor resposta pode variar. Experimentar:
List<? extends Object> list = getList();
return (List<Customer>) list;
ou
List list = getList();
return (List<Customer>) list;
Mas tenha em mente que não é recomendável fazer essas conversões não verificadas.
Com Java 8 Streams :
Às vezes, o lançamento de força bruta é bom:
List<MyClass> mythings = (List<MyClass>) (Object) objects
Mas aqui está uma solução mais versátil:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
Há muitos benefícios, mas um é que você pode lançar sua lista de maneira mais elegante se não tiver certeza do que ela contém:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
funcionou para mim.
Você pode usar um elenco duplo.
return (List<Customer>) (List) getList();
Observe que não sou um programador java, mas em .NET e C #, esse recurso é chamado de contravariância ou covariância. Ainda não me aprofundei nessas coisas, já que são novas no .NET 4.0, que não estou usando porque é apenas beta, então não sei qual dos dois termos descreve o seu problema, mas deixe-me descrever o problema técnico com isso.
Vamos supor que você tenha permissão para lançar. Observe, eu digo elenco , já que foi o que você disse, mas há duas operações que poderiam ser possíveis, casting e conversão .
A conversão significaria que você obteria um novo objeto de lista, mas você diria fundição, o que significa que deseja tratar temporariamente um objeto como outro tipo.
Aqui está o problema com isso.
O que aconteceria se o seguinte fosse permitido (observe, estou assumindo que antes do elenco, a lista de objetos na verdade contém apenas objetos do Cliente, caso contrário, o elenco não funcionaria mesmo nesta versão hipotética de java):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
Nesse caso, isso tentaria tratar um objeto, que não é um cliente, como um cliente, e você obteria um erro de tempo de execução em um ponto, seja do formulário dentro da lista ou da atribuição.
Os genéricos, no entanto, devem fornecer tipos de dados seguros para tipos, como coleções, e como gostam de usar a palavra "garantido", esse tipo de conversão, com os problemas que se seguem, não é permitido.
No .NET 4.0 (eu sei, sua pergunta era sobre java), isso será permitido em alguns casos bem específicos , onde o compilador pode garantir que as operações que você faz são seguras, mas no sentido geral, este tipo de elenco não vai ser permitido. O mesmo vale para java, embora eu não tenha certeza sobre quaisquer planos para introduzir co- e contravariância para a linguagem java.
Esperançosamente, alguém com melhor conhecimento em java do que eu pode lhe dizer os detalhes para o futuro ou implementação 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;
Você não pode porque List<Object>
e List<Customer>
não estão na mesma árvore de herança.
Você poderia adicionar um novo construtor à sua List<Customer>
classe que leva a List<Object>
e, em seguida, iterar pela lista, convertendo cada Object
um em a Customer
e adicionando-o à sua coleção. Esteja ciente de que uma exceção de conversão inválida pode ocorrer se o chamador List<Object>
contiver algo que não seja um Customer
.
O objetivo das listas genéricas é restringi-las a certos tipos. Você está tentando pegar uma lista que pode conter qualquer coisa (Pedidos, Produtos, etc.) e comprimi-la em uma lista que pode conter apenas Clientes.
Sua melhor aposta é criar um novo List<Customer>
, iterar através do List<Object>
, adicionar cada item à nova lista e devolvê-lo.
Como outros apontaram, você não pode conjurá-los de maneira segura, já que a List<Object>
não é a List<Customer>
. O que você pode fazer é definir uma visualização na lista que faça a verificação de tipo no local. Usando coleções do Google que seriam:
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.
}
});
Semelhante ao Bozho acima. Você pode fazer alguma solução alternativa aqui (embora eu mesmo não goste) por meio deste método:
public <T> List<T> convert(List list, T t){
return list;
}
Sim. Ele vai lançar sua lista em seu tipo genérico exigido.
No caso fornecido acima, você pode fazer algum código como este:
List<Object> list = getList();
return convert(list, new Customer());
Dependendo do que você deseja fazer com a lista, pode nem ser necessário convertê-la em a List<Customer>
. Se você deseja apenas adicionar Customer
objetos à lista, pode declará-lo da seguinte maneira:
...
List<Object> list = getList();
return (List<? super Customer>) list;
Isso é legal (bem, não apenas legal, mas correto - a lista é de "algum supertipo para o cliente"), e se você for transferi-la para um método que apenas adicionará objetos à lista, então o acima limites genéricos são suficientes para isso.
Por outro lado, se você deseja recuperar objetos da lista e tê-los fortemente tipados como Clientes - então você está sem sorte, e com razão. Como a lista é um, List<Object>
não há garantia de que os conteúdos sejam clientes, então você terá que fornecer seu próprio elenco na recuperação. (Ou esteja realmente, absolutamente, duplamente certo de que a lista só conterá Customers
e usará um duplo elenco de uma das outras respostas, mas perceba que você está contornando completamente a segurança de tipo em tempo de compilação que obtém dos genéricos neste caso).
Em termos gerais, é sempre bom considerar os limites genéricos mais amplos possíveis que seriam aceitáveis ao escrever um método, duplamente se for usado como um método de biblioteca. Se você for ler apenas de uma lista, use em List<? extends T>
vez de List<T>
, por exemplo - isso dá aos chamadores muito mais escopo nos argumentos que podem passar e significa que eles são menos propensos a encontrar problemas evitáveis semelhantes ao que você ' está tendo aqui.