2012-02-28 2 views

ответ

11

Да.

List<Base> может содержать смесь разных вещей, которые производятся от Base. List<? extend Base> содержит однородные элементы (в том смысле, что они все должны быть получены из определенного, неизвестного типа, который в свою очередь происходит от Base).

Иными словами, List<? extends Base> является базовым классом для List<T extends Base>. Таким образом, вы можете передать List<T extends Base> любому методу, который принимает List<? extends Base>. То же самое не относится к методам, которые принимают List<Base>.

+6

В частности, вы не можете добавить объект типа 'Base' в' List '. –

+3

@LouisWasserman: Не только это, но вы не можете добавить * any * object (кроме 'null') в' List ', потому что вы не знаете, какой тип представляет символ'? '. –

+0

@LouisWasserman: Короче говоря, List может быть передан любому методу, который принимает либо List , Список , Список , или Список ? Тогда зачем кому-то хотеть использовать List ? Меня также озадачивает то, что вы можете сделать .add (...) в обоих List и List , где «...» может быть любым, что является базовым или производным (прямо или косвенно) от Base. – user113454

5

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>.

Опять же, я должен указать - ограниченный шаблон в основном обозначен для общих параметров метода, а не для типов возвращаемых методов или деклараций переменных.

Смежные вопросы