2015-12-15 3 views
1

Таким образом, функция ниже должна быть функцией, которая принимает объект Car и добавляет его к объекту Col<>.Может ли метод с использованием супер взять подтип объекта и добавить его в список?

void insertCar(List<? super Car> c, Car x) { 
    c.add(x) 
} 

Вопрос спрашивает, может ли при добавлении переменной n го типа Nissan объекта к переменной c типа List<Car> будет работать (то есть. insertCar(c, n))

Ответ: Да, но я не знаю, почему. Я думал, что добавление подтипов объекта Car было бы невозможным из-за использования super. То, что он будет принимать типы типа Car или любого супертипа Car.

Любой, кто может меня понять?

EDIT Разве что ...

я не смог бы добавить Nissan, если сам List<> был какой-то другой подтип передается в? Например, если List<? super Car> был фактически List<? super Ford>

Ниже представлены противоречивые ответы ниже, но это вопрос, предоставленный для экзамена, так, чтобы он был уверен, что предоставленный вопрос и ответ верны. Это просто мое понимание того, о чем я не уверен.

+0

'Nissan' является подтипом' Car'? – user1803551

+0

Да, это подтип автомобиля – cpd1

+1

, если Nissan является подтипом автомобиля, тогда ответ NOOoo, Col is not Col

ответ

1

Вопрос спрашивает, может ли при добавлении переменной 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 типа проверки нужно сделать:

  1. Является ли List<Car> действительным первым аргументом insertCar «s List<? super Car>? Да, это подтип, например, here.
  2. Действительно ли Nissan действительный 2-й аргумент для insertCarCar? Да, это подтип.
  3. Действительно ли звонок 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, и это не имеет отношения к содержанию метода.

+0

Правильно, вот почему я смущен. Разве что я могу передать ему автомобиль, но если список был фактически List Я бы не смог передать объект Nissan? Я пытаюсь сделать это в коде из того, что вы предоставили. – cpd1

+0

@ cpd1 Что такое 'C '? Вы хотите изменить определение 'c' в списке аргументов или как определено в' main' (вы назвали их как 'c')? – user1803551

+0

Извините, что это должен был быть список. Я думаю, что я просто не понимаю, что происходит. Я не помню, чтобы это обсуждалось вообще в классе, так что все еще было запутано, почему оно работает так, как оно есть. Я подумал о том, чтобы изменить список на некоторый подтип автомобиля, который не Nissan, что он не сработает, что и было. Но по той же логике я попробовал List , но я не смог добавить Nissan – cpd1

0

Ответ да, но я не уверен, почему. Я думал, что добавление подтипов объекта «Автомобиль» было бы невозможным из-за использования супер. То, что потребовалось бы только типам автомобилей или любому супертипу автомобиля.

Любая ссылка суперкласса может содержать объект его экземпляра или любой его экземпляр дочернего класса, и, следовательно, это полностью законно.

+0

, вам, вероятно, нужно проверить, какой тип co-contravriant –

+0

Хорошо, я думаю, что, возможно, было недоразумением, так как я испытываю стресс. Правильно ли я в том, что проблема заключается в том, что я не смог бы добавить Nissan, если бы сам Col <> был каким-то другим подтипом? Например, если Col был фактически Col cpd1

0

Ваш объект-подтип будет иметь по крайней мере все атрибуты и методы объекта Car, а также, как правило, больше собственных методов. Если объекту Nissan присвоена переменная Car, вы можете вызвать все методы переменной Car. Напротив, присвоение экземпляра автомобиля объекту Nissan было бы невозможным, поскольку объект Nissan мог иметь больше методов, чем экземпляр автомобиля.

+1

, вам, вероятно, нужно больше узнать о дженериках –