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