WildCard в сигнатуре метода
<T extends A> void foo(List<T> list) {}
почему такой синтаксис допустим
<T super A> void foo(List<T> list) {}
но такой нет? Также хотелось бы увидеть объяснение простым языком (если можно с примерами) почему добавление в
List<? extends B> list = new ArrayList<A>();
list запрещено, хотя в docs java вижу следующее
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
transient Object[] elementData; // non-private to simplify nested class access
Разве не любой элемент может быть добавлен в массив Object[]? Конкретнее хотелось бы узнать какой механизм препятствует добавлению.
P.S. Иерархия следующая A>B>C C - потомок B
Прошу, если можете объясните подробнее и как можно проще. Пытался изучить этот момент у Брюса Эккеля, много нагуглил, но толку 0
Ответы (2 шт):
По второй части вопроса. Возьмём такой пример:
List<? extends Number> list = new ArrayList<>();
По умолчанию создаётся такой объект:
new ArrayList<Number>();
А мог бы лежать
new ArrayList<Integer>();
И если мы попробуем добавить, к примеру, 3.5f, то в первом случае всё было бы ок, во втором - ошибка привидения типов. Поэтому в Java существует механизм защиты, при котором ты гарантированно не получишь RuntimeException.
Но в list можно добавить null ---> довольствуйся этим ;/)
Также посоветую ознакомиться с принципом PECS вот здесь.
- P - producer
- E - extends
- C - consumer
- S - super
Вся соль в том, что если вы хотите взаимодействовать с элементами переданного списка, вам необходимо использовать конструкцию вида <? extends SomeClass>. А если вы хотите добавить элементы в переданный список, то тогда вот так: <? super SomeClass>.
Для взаимодействия с элементами вы должны быть уверены, что у этих элементов можно вызвать нужный вам метод. Например, есть класс Cat, у которого есть метод meow(). Передавайте в параметры <? extends Cat>, потому что даже если вам передадут список наследников Cat, у них всё равно будет метод meow().
С добавлением ситуация обратная. Вы можете добавить в List<Cat> экземпляр класса Lion extends Cat, но вы не можете добавить в List<Lion> экземпляр класса Cat. Именно поэтому, если вы хотите добавить в переданный список парочку львов, переданный список должен быть такого вида: List<? super Lion>.