Обобщения Java: список <Container <? >> = новый LinkedList <Container <Double>> () запрещен? - PullRequest
11 голосов
/ 13 января 2009

Как получилось, на 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. Только если я передам что-то, что не является ни Comparable, ни Serializable, оно будет работать правильно.

Конечно, я могу поставить приведение и заставить компилятор замолчать, но мне интересно, делаю ли я здесь что-то не так.

Ответы [ 3 ]

13 голосов
/ 13 января 2009

Каждая параметризация должна быть подстановочными:

List<? extends Container<?>> list = new LinkedList<Container<Double>>();

Редактировать: Я искал в FAQ Анжелики Лангер объяснение, но не нашел его (оно, вероятно, там, но скрывается где-то на 500 страницах).

Способ думать об этом заключается в том, что каждая параметризация независима, и компилятор не будет выводить информацию о параметризации, если вы явно не скажете сделать это.

2 голосов
/ 29 апреля 2009

Подумайте, что бы случилось, если бы вы могли.

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

2 голосов
/ 13 января 2009

Редактировать: Я искал объяснения в часто задаваемых вопросах Анжелики Лангер, но не нашел (возможно, он там есть, но прячется где-то на 500 страницах).

Большое спасибо за ответ. Я нашел объяснение в FAQ, и, посмотрев на него, думаю, я его понял.

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20do%20multilevel%20wildcards%20mean?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...