Поскольку на этот вопрос часто ссылаются, и текущие ответы в основном объясняют, почему он не работает (или предлагают хакерские, опасные решения, которые мне никогда не хотелось бы видеть в рабочем коде), я думаю, что это уместно добавить еще один ответ, показывая подводные камни и возможное решение.
Причина, по которой это не работает в целом, уже указана в других ответах: действительно ли преобразование действительно выполняется, зависит от типов объектов, которые содержатся в исходном списке. Если в списке есть объекты, тип которых не относится к типу TestB
, но относится к другому подклассу TestA
, тогда приведение типа не допустимо.
Конечно, приведение может быть действительным. Иногда у вас есть информация о типах, которые недоступны для компилятора. В этих случаях можно создавать списки, но в общем случае не рекомендуется :
Можно было бы либо ...
- ... разыграть весь список или
- ... приведение всех элементов списка
Последствия первого подхода (который соответствует принятому в настоящее время ответу) неуловимы. На первый взгляд может показаться, что он работает правильно. Но если в списке ввода есть неправильные типы, то будет выдан ClassCastException
, возможно, в совершенно другом месте кода, и это может быть трудно отладить и выяснить, где неправильный элемент попал в список , Худшая проблема заключается в том, что кто-то может даже добавить недопустимые элементы после списка, который был приведен, что делает отладку еще более сложной.
Проблема отладки этих ложных ClassCastExceptions
может быть решена с помощью семейства методов Collections#checkedCollection
.
Фильтрация списка по типу
Более безопасный для типов способ преобразования из List<Supertype>
в List<Subtype>
состоит в том, чтобы фактически отфильтровать список и создать новый список, содержащий только элементы определенного типа. Существует несколько степеней свободы для реализации такого метода (например, в отношении обработки null
записей), но одна из возможных реализаций может выглядеть следующим образом:
/**
* 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;
}
Этот метод может использоваться для фильтрации произвольных списков (не только с заданным отношением Подтип-Супертип относительно параметров типа), как в этом примере:
// 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]