Ответ 1
Бросок не нужен.
Назначения
ArrayList<?> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Integer>();
не требует явного литья.
Подстановочные типы - это "более общие" / "менее конкретные" типы, чем конкретные типы, и верхние ограниченные типы подстановок (например, ? extends Number
) более специфичны, чем неограниченные (?
).
Более подробную информацию о связи между типами подстановочных знаков можно найти в Учебник Oracle по подстановочным символам и подтипированию.
Соответствующая часть JLS, определяющая это, 4.10.2. Подтипирование между классами и типами интерфейсов
Учитывая объявление общего типа C (n > 0), прямые супертипы параметризованного типа C, где Ti (1 ≤ я ≤ n) являются типом, являются следующими:
- D, где D - общий тип, являющийся прямым супертипом общего типа C, а θ - подстановка [F1: = T1,..., Fn: = Tn].
- C, где Si содержит Ti (1 ≤ я ≤ n) (п. 4.5.1).
[...]
который относится к 4.5.1. Тип Аргументы параметризованных типов
Говорят, что аргумент типа T1 содержит другой аргумент типа T2, написанный T2 <= T1, если набор типов, обозначаемый T2, является предположительно подмножеством множества типов, обозначаемых T1 при рефлексивном и транзитивном замыкании следующие правила (где <: обозначает подтипирование (§4.10)):
? расширяет T < =? расширяет S, если T <: S
? расширяет T < =?
[...]
Таким образом, это определение ArrayList<? extends Number>
является супертипом ArrayList<Integer>
, а ArrayList<?>
является супертипом любого ArrayList<>
, за исключением исходного типа.
Назначение переменной типа, являющегося супертипом, не требует кастинга.
Приведение требуется, если вы хотите присвоить что-то другого типа:
Object list = new ArrayList<Integer>();
//...somewhere else - the compiler does not know that list is always an ArrayList, but we tell it that we know what we are doing
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but works
После этого акта вы можете, например, получить элементы из списка и рассматривать их как Number
s. При выполнении команды cast при выполнении задания list
, которое не является подтипом List<? extends Number>
Object list = new HashSet<Integer>();
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning
не выполняется при запуске
java.lang.ClassCastException: java.util.HashSet cannot be cast to java.util.List
Проблемы возникают, когда общий тип не соответствует:
List<String> stringList = new ArrayList<String>();
stringList.add("hi");
Object list = stringList;
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works
Number n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
Это происходит потому, что во время выполнения стирается стирание типов списка. См. Также учебник по стиранию