недоразумение generi c при привязывании к списку - PullRequest
0 голосов
/ 02 мая 2020

это подстановочный вопрос.

Моя цель состоит в том, чтобы создать список, содержащий класс общего типа c с расширенными примерами:

так это структура:

  public class Event<T extends ActionType>{
  }

  public abstract class ActionType{
  }

  //**many** classes that extends ActionType class

это список, содержащий классы, которые расширяются от ActionType

  private List<Event<ActionType>> list = ArrayList<>();

  Event<RightClick> event = new Event<>(xPosition, yPosition, delay, new RightClick(robot), clicks, robot);

  list.add(event);

Я знаю, что не могу сделать это, чтобы убедиться, что Я могу добавить расширенные элементы:

  private List<Event<ActionType>> list = ArrayList<>();

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

, чтобы исправить моя проблема, я использовал подстановочный знак селектор ?

 List<Event<? extends ActionType>>

1 Ответ

1 голос
/ 02 мая 2020

Пояснение

Обобщения инвариант . A List<Event<ActionType>> не будет принимать Event<RightClick>, только Event<ActionType>.

. Понимать дженерики и корректировать ограничения типа c дженериков.

Если дженерики будут ковариантными , тогда вы могли бы дать кому-то, кто ожидает List<Animal> a List<Dog>, а затем добавить Cat s к нему. Что может вызвать повреждение кучи , поскольку dogs.get(0) может внезапно стать Cat.

Пример:

List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());

List<Animal> animals = dogs; // pretend this would work
animals.add(new Cat()); // would be legit

Dog dog = dogs.get(1); // should be safe, but is cat, heap corruption

A List<Animal> явно говорит, что этот список должен принять всех животных, а также кошек. Но List<Dog> ограничен только для собак. Два списка ведут себя по-разному, они имеют разные ограничения, поэтому вы не можете использовать один для другого. В отличие от Dog, который является Animal, List<Dog> не является List<Animal>, то есть то, что подразумевается под коинвариантностью и инвариантностью.


Решение

Правильный инструмент для "принять любые ActionType, мне все равно" являются подстановочными знаками . Так что либо go с

 List<Event<? extends ActionType>>

или просто

List<Event<?>>

, так как класс Event уже определяет ограничение T extends ActionType.

С этим типом вы к нему можно будет добавить все виды Event s:

Event<RightClick> rightClick = ...
Event<LeftClick> leftClick = ...
Event<MiddleClick> middleClick = ...

list.add(rightClick);
list.add(leftClick);
list.add(middleClick);

В результате использования подстановочного знака ? вы больше не сможете знать фактический тип во время компиляции, поэтому :

Event<?> event = list.get(0); // unknown which exact type

Все, что вам известно о ?, это то, что оно по крайней мере extends ActionType, так что вы сможете использовать все виды методов, которые даются ActionType, но ничего не вводится только в RightClick например. Для этого потребовалось бы явное приведение (защищенное проверкой instanceof), хотя я бы поставил под сомнение ваш дизайн, если вам придется использовать указание правой кнопкой мыши c вещей там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...