Java generics: List <Container <? > >= new LinkedList <Контейнер <Double>>() запрещен?
Итак, на Java я могу написать
List<?> list = new LinkedList<Double>();
но не
List<Container<?>> list = new LinkedList<Container<Double>>();
где Контейнер - это что-то вроде
public class Container<T> { ... }
Это произошло потому, что у меня есть метод, который принимает List<Container<?>>
, и я хотел бы использовать Arrays.asList для передачи ему аргументов:
process(Arrays.asList(new Container<Double>(), new Container<Double>()));
Но язык не позволяет этого, потому что он указывает тип Arrays.asList
на List<Container<Double>>
, и это не присваивается List<Container<?>>
.
Если я добавляю к вызову контейнер с параметрами String,
process(Arrays.asList(new Container<Double>(), new Container<String>()));
он по-прежнему не работает, поскольку он отображает тип List<Container<? extends Serializable & Comparable<?>>>
для Arrays.asList. Только если я передаю что-то, что не является ни сравнимым, ни Serializable, оно работает правильно.
Конечно, я могу добавить в литье и заставить компилятор заткнуться, но мне интересно, не делаю ли я здесь что-то не так.
Ответы
Ответ 1
Каждая параметризация должна быть подстановочна:
List<? extends Container<?>> list = new LinkedList<Container<Double>>();
Изменить: я искал Анжелика Лангер FAQ для объяснения, но не нашел его (возможно, там, но скрывается где-то в 500 страниц).
Способ думать об этом заключается в том, что каждая параметризация независима, и компилятор не будет выводить информацию о параметризации, если вы явно не говорите об этом.
Ответ 2
Изменить: я искал в Angelika Langer FAQ для объяснения, но не нашел его (возможно, там, но скрывается где-то на 500 страницах).
Большое спасибо за ответ. Я нашел объяснение в FAQ, и после некоторого прищуривания я думаю, что получаю его.
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20do%20multilevel%20wildcards%20mean?
Ответ 3
Подумайте, что произойдет, если сможете.
List<Container<Double>> list1 = new LinkedList<Container<Double>>();
List<Container<?>> list2 = list1; // this shouldn't be allowed, because of the below
Container<String> foo = new Container<String>();
foo.add("hi");
list2.add(foo); // legal, because Container<String> is a subtype of Container<?>
Container<Double> bar = list1.get(0);
Double x = bar.get(0); // type error; it is actually a String object
// this indicates that type safety was violated
Однако использование List<? extends Container<?>>
не имеет этой проблемы, потому что вы не можете поместить что-либо (кроме null
) в список этого типа (потому что нет типа, который гарантированно является подтипом "? extends Container<?>
" ).