Java generics, вложенный набор подстановочных знаков
Это компилирует (1.6)
List<? extends Object> l = new ArrayList<Date>();
Но это не
List<List<? extends Object>> ll = new ArrayList<List<Date>>();
с ошибкой
Type mismatch: cannot convert from ArrayList<List<Date>> to List<List<? extends Object>>
Может кто-нибудь объяснить, почему?
Благодаря
EDIT: отредактирован для последующего
Ответы
Ответ 1
Потому что это нарушит безопасность типа:
List<List<Object>> lo = new ArrayList<List<Object>>();
List<List<? extends Object>> ll = lo;
List<String> ls = new ArrayList<String>();
ll.add(ls);
lo.get(0).add(new Object());
String s = ls.get(0); // assigns a plain Object instance to a String reference
Ответ 2
Хорошо объяснения верны, но я думаю, было бы неплохо добавить и фактическое рабочее решение;)
List<? extends List<? extends Object>>
Будет работать отлично, но, очевидно, использование такой коллекции довольно ограничено обычными ограничениями общих коллекций (но тогда то же самое верно для более простой List <? extends Date > )
Ответ 3
Предположим, что D
является подтипом B
, G<T>
является общим типом
B x = new D(); // OK
G<B> y = new G<D>(); // FAIL
Теперь G<Date>
является подтипом G<?>
, поэтому
G<?> x = new G<Date>(); // OK
G<G<?>> y = new G<G<Date>>(); // FAIL
Ответ 4
<? extends Object>
означает, что подстановочный знак может быть заменен только для тех объектов, которые являются подклассом класса Object
.
List<List<? extends Object>> ll = new ArrayList<List<Object>>();
дает вам ошибку несоответствия типов, потому что вы пытаетесь назначить ArrayList
из списка объектов класса java Object
на List
, который содержит List
любого типа объектов, которые являются подклассом java класс Object
.
Для получения дополнительной информации см. Подстановочная документация
Ответ 5
При назначении переменной (List<T>
) с несимвольным общим типом T
назначаемый объект должен иметь ровно T
как свой общий тип (включая все параметры типового типа T
, подстановочный знак и несимвольный). В вашем случае T
есть List<? extends Object>
, который не совпадает с типом List<Date>
.
Что вы можете сделать, потому что List<Date>
присваивается List<? extends Object>
, используется тип подстановочного знака:
List<? extends List<? extends Object>> a = new ArrayList<List<Date>>();