Дженерики в коллекции
Вот моя программа. Я не уверен, почему я получаю ошибку времени компиляции.
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List< ? extends Number > list = new ArrayList<Integer>();
list.add(6); // Compile Time Error
System.out.println(list);
}
}
Но следующая программа отлично работает
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List< ? super Number > list = new ArrayList<Number>();
list.add(6);
System.out.println(list);
}
}
Ошибка с Eclipse:
Вот описание ошибки из Eclipse:
Метод add (int, capture # 1-of? extends Number) в типе List is not применимо для аргументов (int)
Ответы
Ответ 1
Это потому, что то, что вы делаете в первом случае , не безопасно для типов. Вы объявили list
как list
для "некоторого подкласса Number
", а затем попытались вставить в него Integer
. Нет абсолютно никакой гарантии, что Integer
совместим с фактическим типом времени выполнения базового списка. Компилятор останавливает вас здесь, потому что то, что вы делаете , не имеет смысла.
Рассмотрим в качестве крайнего примера:
List< ? extends Object > list = new ArrayList<Integer>();
list.add("Hello, World!");
Если это сработает, у вас будет List<Integer>
с String
в нем!
Если вы действительно хотите, чтобы он работал, вы должны сообщить компилятору, что знаете, что делаете, кастинг:
((List<Integer>)list).add(6);
Но даже тогда вы все равно получите предупреждение о безопасности типов.
Второй случай работает, потому что в списке гарантируется "некоторый суперкласс из числа". Integer
является подклассом Number
, поэтому он может быть неявно преобразован в любой суперкласс (включая сам Number
), поэтому нет риска, что это значение несовместимо с фактическим типом списка.
Для получения дополнительной информации вы можете прочитать разницу между ковариацией и контравариантностью.
Ответ 2
Вы не можете добавить что-либо к List
, у которого есть ? extends ...
как часть своего типового типа.
Посмотрите на это:
List< ? extends Number > list = new ArrayList<Integer>();
Обратите внимание, что фактический List
, который вы используете, - это ArrayList<Integer>
. Невозможно добавить что-то еще в этот список, который не является Integer
. Тем не менее, тип List<? extends Number>
позволит вам добавить в список, например, Double
, потому что Double
также расширяет Number
.
Подробнее об этом см. в разделе "Часто задаваемые вопросы по Java Generics" в Angelika Langer: Какие методы и поля доступны/недоступны через ссылочную переменную с параметризованным типом подстановочного знака?
Ответ 3
Его о super
и extends
. Сравните этот вопрос.
вы также можете найти его Wildcards.
Ответ 4
Это не работает:
List< ? extends Number > list = new ArrayList<Integer>();
list.add(6); // Compile Time Error
потому что если бы это произошло, вы могли бы прийти в такую ситуацию.
class Apple extends Number {}
List< ? extends Number > list = new ArrayList<Integer>();
list.add(new Apple()); //if it were to work, you'd have apples in what you'd think was a list of integers