И <?>
и <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
, так как они же экземпляр.
Downvoter: помочь объяснить? –