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<?>" ).