Java Общий тип: разница между List <? extends Number> и List <T extends Number>
Java Общий тип: в чем разница между
(1) List <? extends Number>
(2) List <T extends Number>
согласно моему пониманию
(1) List <? extends Number>
- это
Readonly Список "неизвестных" типов данных с суперклассом "Число". мы можем прочитать только элемент, но не можем добавить
(2) List <T extends Number>
Список типов данных с суперклассом "Число". мы можем читать и добавлять элементы в список
См. пример ниже кода
class TestGen{
public static void main(String[] args) {
double result = 0.0;
List<Integer> intList = new ArrayList<Integer>();
intList.add(10);
intList.add(20);
intList.add(30);
result = TestGen.sumOfList1(intList);
System.out.println("Result=" + result);
result = TestGen.sumOfList2(intList);
System.out.println("Result=" + result);
}
public static double sumOfList1(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
public static <T extends Number> double sumOfList2(List<T> list) {
double s = 0.0;
// -- ---------------------------------------------------------
// getting error while trying to add new element
// list<T> is not applicable for argument(Integer) : Why ?
list.add(new Integer(40));
for (Number n : list)
s += n.doubleValue();
return s;
}
}
Когда я пытаюсь добавить Integer (или даже объект Number) в sumOfList2, то получаю ошибку. Пожалуйста, объясните, что здесь не так?
Ответы
Ответ 1
Основное отличие заключается в том, что вы используете T extends Number
, тогда вы можете обратиться к типу T
Например: list.add((T) new Integer(40));
Если вы используете ? extends Number
, то вы не можете ссылаться на этот тип, но вы все равно можете сказать ((List<Integer>)list).add((int) s);
Ответ 2
В отдельности нет большой разницы. Однако два экземпляра List<? extends Number>
в одном контексте полностью не связаны друг с другом, а два экземпляра List<T extends Number>
в одном контексте относятся к одному и тому же T
и тому же интерфейсу.
public void addAll(List<? extends Number> to, List<? extends Number> from) {
for (Number n: from) {
to.add(n);
}
}
Этот метод терпит неудачу, потому что n
не может быть добавлен в to
, а также не удалось, поскольку типы членов from
и to
могут быть совершенно разными.
public <T> void addAll(List<T extends Number> to, List<T extends Number> from) {
for (T n: from) {
to.add(n);
}
}
Этот метод отлично компилируется. Это не обязательно; Collections
имеет лучшую версию, но будет работать без ошибок.
Ответ 3
В sumOfList2
, T
является конкретным подклассом Number
, но он может быть любым из них. Например T
может быть BigDecimal
, и вы не можете добавить Integer
в List<BigDecimal>
.
Если вы хотите добавить любые числа в список, это должно быть List<Number>
:
public static double sumOfList2(List<Number> list) {...}
Ответ 4
Первый случай очень прост и известен из T extends Number
, что T - это объект, который относится к типу Number Number или его дочернему элементу.
Это означает, что если у нас есть метод, который использует T как тип Number, мы можем манипулировать нашим методом соответственно i.e
<T extends Number> void myMethod ( List <T> num){
num.add(1); // 1 is an Integer
num.add(2.3) // 2.3 is a Double
}
Но в этом * Диком характере '?' * Если мы не знаем, на какой объект будет ссылаться, даже если он расширяет число, но может быть любым объектом Object
void myMethod( List <? extends Number> num){
// num.add(1); // not a valid statement, as we dont know if '1' is of the type '?'
// num.add(2.3) // not a valid statement, as we dont know if '2.3' is of the type '?'
}
Таким образом, единственное значение, которое может быть записано в таких выражениях, - null, поскольку любой тип объекта может быть нулевым.
void myMethod( List <? extends Number> num){
num.add(null)
}
Такие методы являются методами только для чтения.