Generics: Почему приведение с подстановочными знаками и наоборот разрешено в методе передачи параметров?
У меня есть следующий код:
public static void swap(List<?> list) {
swapHelper(list); //1
}
private static <E> void swapHelper(List<E> list) {
swap(list); //2
}
{
List<?> tW = new ArrayList<>();
List<E> tE = new ArrayList<>();
tW = tE; // 3
tE = tW; // 4
}
В этом коде строки 1 и 2 успешно компилируются, не значит ли это: я могу назначить ссылки на List<?>
к тому из List<E>
и наоборот? Если так, то почему строка 4 не компилируется.
1 ответ
И то и другое <?>
а также <E>
неизвестные типы; но все List<?>
s имеют элементы некоторого типа, так что вы можете вызвать метод, чей параметр List<E>
потому что есть какой-то неизвестный тип, который соответствует ему.
Обратите внимание, что вы не можете сделать это:
public static void swap(Object object, List<?> list) {
swapHelper(object, list); // Compiler error: object not in bounds of list.
}
private static <E> void swapHelper(E object, List<E> list) {
swap(object, list); // OK.
}
потому что теперь вы не знаете, если Object
находится в пределах List<?>
,
Также вы не можете добавить новые ненулевые значения в список:
private static <E> void swapHelper(List<E> list) {
list.add(new E()); // Can't create an instance of type variable.
swap(list);
}
но вы можете добавить значения, которые вы берете из списка, поскольку они, как известно, находятся в пределах списка:
private static <E> void swapHelper(List<E> list) {
list.add(list.get(0));
swap(list);
}
так что это тип безопасно сделать вызов оригинала swapHelper
от swap
, поскольку вы не можете вызвать что-то, что не поддается E
(каким бы ни был этот тип) в список.
Аналогично с tW
а также tE
:
- Если вы назначите
tW = tE
Вы не можете ничего добавить кtW
Кроме какnull
так что нельзя поставитьtE
в состоянии, где он содержит что-либо, кроме случаевE
, - Если вам было разрешено назначить
tE = tW
Вы можете добавить ненулевые экземплярыE
вtE
, Это может означать, что вы можете добавить экземпляр неправильного класса вtW
, что может привести к ошибкам типа во время выполнения. Таким образом, это назначение запрещено.
Помните, что назначение списка не приводит к копированию списка: если вы назначаете tE = tW
, затем tE == tW
так что все изменения применяются к tE
также видны через tW
, так как они один и тот же экземпляр.