Java: литье объекта в общий тип
В Java при отбрасывании из объекта в другие типы, почему вторая строка создает предупреждение, относящееся к приведению, но первое не работает?
void a(Object o) {
Integer i = (Integer) o;
List<Integer> list = (List<Integer>) o;
}
/*Type safety: Unchecked cast from Object to List<Integer>*/
Ответы
Ответ 1
Это потому, что объект не будет проверяться на наличие List<Integer>
во время выполнения из-за стирания типа. Это будет просто отбрасывание на List
. Например:
List<String> strings = new ArrayList<String>();
strings.add("x");
Object o = strings;
// Warning, but will succeeed at execution time
List<Integer> integers = (List<Integer>) o;
Integer i = integers.get(0); // Bang!
Подробнее см. Часто задаваемые вопросы по Java Generics Angelika Langer, в частности раздел стирания стилей.
Ответ 2
Для ясности позвольте мне немного переписать примеры...
Я бы сказал, ключевое различие между:
void a(Object o) {
Integer i = (Integer) o;
...
}
и
void a(Object o) {
List<Integer> list = (List<Integer>) o;
...
}
заключается в том, что при условии, что существует ошибка типа, первый приведение всегда сразу бросает исключение RuntimeException (в частности, ClassCastException) при выполнении.
В то время как второй может отсутствовать - если входной параметр o является любым типом List<?>
, выполнение будет продолжаться, несмотря на неправильного литая.
Будет ли код где-нибудь позже выдавать исключение или нет, зависит от того, что вы делаете со списком.
Но независимо от того, что Exception может не быть брошенным на строку, в которой был сделан актерский состав, но где-то еще (что может быть сложной ошибкой для отслеживания) или вообще нет.
То, что я понимаю, является причиной того, что разработчики-компиляторы считали предупреждение подходящим только во втором случае.
Ответ 3
Ответ Jon - правильный, но иногда вы не можете обойти это предупреждение (например, когда вы работаете с устаревшим API). В таких случаях вы можете подавить предупреждение так:
@SuppressWarnings("unchecked")
List<Integer> list = (List<Integer>) someApiThatReturnsNonGenericList();