Это помогло мне увидеть дженерики как ограничения или контракты, а не как типы с подтипами. Таким образом, переменная List<? extends Number> var
говорит: var
— это список некоторого неизвестного типа ?
, который должен быть подтипом Number.
List<Number> listN;
List<Double> listD;
List<? extends Number> listX;
...
Number n1 = ...;
Double d1 = ...;
...
listN.add(n1); // OK n1 is a Number
listN.add(d1); // OK d1 is a Double, which is a Number
listD.add(n1); // compile error, n1 is not a Double
listD.add(d1); // OK
listX.add(n1); // compile error, because the exact type of list is not known! (prevents putting a Dog in a Cat list)
listX.add(d1); // compile error, same cause
Итак, если вы даже не можете поместить число в List<? extends Number>
, в чем смысл такого списка? Он позволяет работать со списками, точный тип которых не имеет значения для поставленной задачи:
// instead of several exactly typed methods...
int count(List<Number> numberList) {...}
int count(List<Object> objectList) {...}
// ...etc. you can have one with a degree of freedom:
int count(List<?> anyList) {...} // don't need to know the exact type of list
// instead of this...
Number sum(List<Number> numberList) {...}
Number sum(List<Double> doubleList) {...}
Number sum(List<Integer> integerList){...}
// you can do this, with a little less freedom in the ?
Number sum(List<? extends Number> list) {
// the only thing we need to know about the list's type is that it is some number type
...
Number ni = list.get(i);
...
}
Использование подстановочных знаков ? extends X
позволяет смягчить жесткие контракты до более слабых условий.
Используя параметр именованного типа, вы можете установить ограничения на разрешенные типы между несколькими переменными:
// works for any type T of list, whatever T is
// T is the same in the argument and in the return
<T> T pickObject(List<T> list, int index) {
return list.get(index);
}
// works for any type T of list, if T is a Number type
// T is the same in the argument and in the return
<T extends Number> T pickNumber(List<T> list, int index) {
return list.get(index);
}
...
List<Number> list;
Number n = pickNumber(list);
person
Markus
schedule
28.05.2015
Double
иInteger
в одном спискеList<? extends Number>
. ИList<Double>
, иList<Integer>
равныList<? extends Number>
, ноList<? extends Number>
не совпадает сList<Number>
. - person aioobe   schedule 28.05.2015Dog
предположительно расширяетAnimal
. - person aioobe   schedule 28.05.2015