Por exemplo, digamos que você tenha duas classes:
public class TestA {}
public class TestB extends TestA{}
Eu tenho um método que retorna List<TestA>
ae gostaria de converter todos os objetos nessa lista para TestB
que eu acabe com a List<TestB>
.
a conversão de genéricos não é possível, mas se você definir a lista de outra maneira, será possível armazenar o TestB nela:
Você ainda tem a verificação de tipo para fazer quando estiver usando os objetos na lista.
fonte
Cannot instantiate the type ArrayList<? extends TestA>
.Você realmente não pode *:
Exemplo é retirado deste tutorial Java
Suponha que existem dois tipos
A
eB
talB extends A
. O código a seguir está correto:O código anterior é válido porque
B
é uma subclasse deA
. Agora, o que acontece comList<A>
eList<B>
?Acontece que
List<B>
não é uma subclasse de,List<A>
portanto, não podemos escreverAlém disso, nem podemos escrever
*: Para possibilitar a transmissão, precisamos de um pai comum para ambos
List<A>
eList<B>
:List<?>
por exemplo. O seguinte é válido:Você receberá, no entanto, um aviso. Você pode suprimi-lo adicionando
@SuppressWarnings("unchecked")
ao seu método.fonte
Com o Java 8, você realmente pode
fonte
new List<TestB>
, um loop e um elenco?Eu acho que você está lançando na direção errada ... se o método retornar uma lista de
TestA
objetos, não será realmente seguro lançá-losTestB
.Basicamente, você está solicitando ao compilador que permita executar
TestB
operações em um tipoTestA
que não as suporta.fonte
Como essa é uma pergunta amplamente referenciada e as respostas atuais explicam principalmente por que ela não funciona (ou propõe soluções perigosas e hacky que eu nunca gostaria de ver no código de produção), acho apropriado adicionar outra resposta, mostrando as armadilhas e uma possível solução.
A razão pela qual isso não funciona em geral já foi apontada em outras respostas: A validade ou não da conversão depende dos tipos de objetos contidos na lista original. Quando houver objetos na lista cujo tipo não seja do tipo
TestB
, mas de uma subclasse diferente deTestA
, a conversão não será válida.Obviamente, os lançamentos podem ser válidos. Às vezes, você tem informações sobre os tipos que não estão disponíveis para o compilador. Nesses casos, é possível lançar as listas, mas, em geral, não é recomendado :
Pode-se também ...
As implicações da primeira abordagem (que corresponde à resposta atualmente aceita) são sutis. Pode parecer funcionar corretamente à primeira vista. Mas se houver tipos errados na lista de entrada, a
ClassCastException
será lançada, talvez em um local completamente diferente no código, e pode ser difícil depurar isso e descobrir onde o elemento errado entrou na lista. O pior problema é que alguém pode até adicionar os elementos inválidos após a lista ser lançada, tornando a depuração ainda mais difícil.O problema de depurar esses espúrios
ClassCastExceptions
pode ser aliviado com aCollections#checkedCollection
família de métodos.Filtrando a lista com base no tipo
Uma maneira mais segura de se converter de um
List<Supertype>
para umList<Subtype>
é filtrar a lista e criar uma nova lista que contenha apenas elementos que tenham determinado tipo. Existem alguns graus de liberdade para a implementação de um método desse tipo (por exemplo, com relação ao tratamento denull
entradas), mas uma possível implementação pode ser assim:Este método pode ser usado para filtrar listas arbitrárias (não apenas com um determinado relacionamento Subtype-Supertype em relação aos parâmetros de tipo), como neste exemplo:
fonte
Você não pode lançar
List<TestB>
aList<TestA>
como Steve Kuo menciona, mas você pode despejar o conteúdo deList<TestA>
dentroList<TestB>
. Tente o seguinte:Eu não tentei esse código, provavelmente há erros, mas a idéia é que ele itere através do objeto de dados, adicionando os elementos (objetos TestB) à Lista. Espero que funcione para você.
fonte
A melhor maneira segura é implementar
AbstractList
e lançar itens na implementação. Eu criei aListUtil
classe auxiliar:Você pode usar o
cast
método para converter objetos às cegas na lista e noconvert
método para transmitir com segurança. Exemplo:fonte
A única maneira que eu sei é copiando:
fonte
Quando você lança uma referência ao objeto, está apenas lançando o tipo da referência, não o tipo do objeto. a conversão não altera o tipo real do objeto.
Java não possui regras implícitas para converter tipos de objetos. (Ao contrário dos primitivos)
Em vez disso, você precisa fornecer como converter um tipo para outro e chamá-lo manualmente.
Isso é mais detalhado do que em um idioma com suporte direto, mas funciona e você não precisa fazer isso com muita frequência.
fonte
se você tiver um objeto da classe
TestA
, não poderá convertê-loTestB
. TodoTestB
é umTestA
, mas não o contrário.no seguinte código:
a segunda linha lançaria a
ClassCastException
.você só pode converter uma
TestA
referência se o próprio objeto forTestB
. por exemplo:portanto, nem sempre você pode converter uma lista
TestA
em uma lista deTestB
.fonte
Você pode usar o
selectInstances
método nas Coleções Eclipse . Isso envolverá a criação de uma nova coleção, no entanto, portanto, não será tão eficiente quanto a solução aceita que usa a conversão.Eu incluí
StringBuffer
no exemplo para mostrar queselectInstances
não apenas o tipo de downcasts, mas também filtrará se a coleção contiver tipos mistos.Nota: Sou um colaborador das Coleções Eclipse.
fonte
Isso é possível devido ao apagamento do tipo. Vai descobrir que
Internamente, ambas as listas são do tipo
List<Object>
. Por esse motivo, você não pode converter um para o outro - não há nada para transmitir.fonte
Integer j = 42; Integer i = (Integer) j;
funciona bem, ambos são números inteiros, ambos têm a mesma classe, portanto "não há nada a transmitir".O problema é que seu método NÃO retorna uma lista de TestA se ele contém um TestB, e daí se ele foi digitado corretamente? Então este elenco:
funciona tão bem quanto você poderia esperar (Eclipse avisa sobre um elenco não verificado, que é exatamente o que você está fazendo, então meh). Então, você pode usar isso para resolver seu problema? Na verdade, você pode por causa disso:
Exatamente o que você pediu, certo? ou para ser realmente exato:
parece compilar muito bem para mim.
fonte
Este teste mostra como transmitir
List<Object>
paraList<MyClass>
. Mas você precisa prestar atenção, poisobjectList
deve conter instâncias do mesmo tipo queMyClass
. E este exemplo pode ser considerado quandoList<T>
é usado. Para esse fim, pegue o campoClass<T> clazz
no construtor e use-o em vez deMyClass.class
.fonte
Isso deveria funcionar
fonte
É bastante estranho que a transmissão manual de uma lista ainda não seja fornecida por alguma caixa de ferramentas que implementa algo como:
Obviamente, isso não verificará os itens um por um, mas é exatamente isso que queremos evitar aqui, se soubermos que nossa implementação fornece apenas o subtipo.
fonte