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 de TestA, 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 ...
- ... lançar a lista inteira ou
- ... lança todos os elementos da lista
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 ClassCastExceptionserá 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 ClassCastExceptionspode ser aliviado com a Collections#checkedCollectionfamília de métodos.
Filtrando a lista com base no tipo
Uma maneira mais segura de se converter de um List<Supertype> para um List<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 de nullentradas), mas uma possível implementação pode ser assim:
/**
* Filter the given list, and create a new list that only contains
* the elements that are (subtypes) of the class c
*
* @param listA The input list
* @param c The class to filter for
* @return The filtered list
*/
private static <T> List<T> filter(List<?> listA, Class<T> c)
{
List<T> listB = new ArrayList<T>();
for (Object a : listA)
{
if (c.isInstance(a))
{
listB.add(c.cast(a));
}
}
return listB;
}
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:
// A list of type "List<Number>" that actually
// contains Integer, Double and Float values
List<Number> mixedNumbers =
new ArrayList<Number>(Arrays.asList(12, 3.4, 5.6f, 78));
// Filter the list, and create a list that contains
// only the Integer values:
List<Integer> integers = filter(mixedNumbers, Integer.class);
System.out.println(integers); // Prints [12, 78]