Вопрос спрашивает, может ли при добавлении переменной n
типа Nissan
объект переменной c
типа List<Car>
будет работать (то есть. insertCar(c, n)
)
Чтобы поместить свои слова в коде, я считаю, что это о чем вы говорите:
public class GenericCheck {
static void insertCar(List<? super Car> c, Car x) {
c.add(x);
}
public static void main(String[] args) {
List<Car> c = new ArrayList<>();
Nissan n = new Nissan();
insertCar(c, n);
}
}
class Car {}
class Nissan extends Car {}
Да. это хорошо, но есть 3 типа проверки нужно сделать:
- Является ли
List<Car>
действительным первым аргументом insertCar
«s List<? super Car>
? Да, это подтип, например, here.
- Действительно ли
Nissan
действительный 2-й аргумент для insertCar
Car
? Да, это подтип.
- Действительно ли звонок
c.add(x)
? Да, аргумент x
должен быть типа Car
или надтипа Car
, как это определено List<? super Car> c
, и это значит, по определению Car x
.
Так почему же это сбивает с толку? Потому что вы переходите ко второму аргументу Nissan
и думаете, что теперь точка 3 сломается, потому что x
не относится к типу Car
или к супертипу Car
(это подтип). Случается, что Nissan
повышается до Car
, что является жизнеспособным аргументом.
Помните, что для того, чтобы узнать, действительно ли звонок c.add(x)
, вам нужно найти определения c
и x
(в списке аргументов метода). Это гарантирует, что до тех пор, пока метод вызывается с допустимыми аргументами, выполняется вызов c.add(x)
. Эта проверка не связана с проверками типа (2) при вызове insertCar
. Это три проверки, которые мы выполнили выше.
Редактировать: Так почему же insertCar(List<? super Nissan> c, Car x)
не работает?
по причине тип стирание. Во время компиляции компилятор стирает все параметры типа и заменяет каждую свою первую оценку (см. here). Что вы получаете - это запрос для List<Nissan>
- add(Car)
. Но это невозможно скомпилировать, потому что Car
не является подтипом Nissan
.
В первом случае List<? super Car>
тип стирания приведет к List<Car>
, а затем add(Car)
.
Что, я думаю, очистит ваше замешательство, а самое главное - это осознание того, что дженерики предоставляют компиляцию только времени. Как я уже упоминал выше блока кода
static void insertCar(List<? super Car /* or Nissan */> c, Car x) {
c.add(x);
}
должен компилировать независимо от того, какие аргументы метод вызывается при выполнения. Это означает, что дженерики в аргументе 1-го метода не имеют ничего общего с типом, который вы передаете второму аргументу: insertCar(..., Car)
или insertCar(..., Nissan)
не влияют на компиляцию c.add(x)
. Данный аргумент преобразуется (upcasted) в аргумент метода типа Car
, и это не имеет отношения к содержанию метода.
'Nissan' является подтипом' Car'? – user1803551
Да, это подтип автомобиля – cpd1
, если Nissan является подтипом автомобиля, тогда ответ NOOoo, Col is not Col super Car> –