List<? extends Base> list
List<Base> list
Есть ли разница между двумя объявлениями?Список <? extends Base> VS List <Base>
Thanks,
List<? extends Base> list
List<Base> list
Есть ли разница между двумя объявлениями?Список <? extends Base> VS List <Base>
Thanks,
Да.
List<Base>
может содержать смесь разных вещей, которые производятся от Base
. List<? extend Base>
содержит однородные элементы (в том смысле, что они все должны быть получены из определенного, неизвестного типа, который в свою очередь происходит от Base
).
Иными словами, List<? extends Base>
является базовым классом для List<T extends Base>
. Таким образом, вы можете передать List<T extends Base>
любому методу, который принимает List<? extends Base>
. То же самое не относится к методам, которые принимают List<Base>
.
List<Base> list
может содержать элементы типа Base
или любые его подтипы. Некоторые примеры с классами JDK:
List<Object> objects = new ArrayList<Object>();
objects.add(new Object()); // adding an Object instance
objects.add("I am a String"); // a String instance is also an Object
objects.add(Integer.valueOf(5)); // an Integer instance is also an Object
Но при извлечении элементов, вы можете назначить их только переменные Object
класса, потому что Object
является параметр типа заявленного списка.
Object first = objects.get(1);
Object second = objects.get(2);
Object third = objects.get(3);
Их реальные классы во время выполнения еще Object
, String
и Integer
, так что вы можете бросить их к тем типам и работать с ними как таковой, но такие броски могут не во время выполнения с ClassCastException
, если не сделано правильно, и это как правило, не рекомендуется работать со списками таким образом.
List<? extends Base> list
является свидетельством того, что на самом деле не предназначен для описания переменных, потому что, как уже говорилось в комментарии Daniel Pryden - вы сможете не add()
любой объект в нем, только null
s.
List<? extends String> list = new ArrayList<? extends String>();
list.add("a String")); // compile error!
Но вы можете использовать такие ограниченного выражение подстановочных для общих параметров методы. Пример из самого List
является addAll()
метод, сигнатура заключается в следующем:
boolean addAll(Collection<? extends E> c);
Это позволяет сделать что-то вроде этого:
List<String> strings = Arrays.asList("a", "b");
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);
<? extend E>
Без шаблона это не было бы возможным, чтобы добавить те String
s в List
из Object
s, поскольку общие типы (в отличие от массивов) не являются covariant. Это означает, что List<String>
не является подтипом List<Object>
. Но любой String
- это Object
, верно? Поэтому поэтому необходимо объявить параметр метода с ограниченным шаблоном - a List<String>
- подтип List<? extends Object>
.
Опять же, я должен указать - ограниченный шаблон в основном обозначен для общих параметров метода, а не для типов возвращаемых методов или деклараций переменных.
В частности, вы не можете добавить объект типа 'Base' в' List extends Base> '. –
@LouisWasserman: Не только это, но вы не можете добавить * any * object (кроме 'null') в' List extends Base> ', потому что вы не знаете, какой тип представляет символ'? '. –
@LouisWasserman: Короче говоря, List extends Base> может быть передан любому методу, который принимает либо List extends Base>, Список , Список , или Список ? Тогда зачем кому-то хотеть использовать List ? Меня также озадачивает то, что вы можете сделать .add (...) в обоих List extends Base> и List , где «...» может быть любым, что является базовым или производным (прямо или косвенно) от Base. –
user113454