Intereting Posts

Списки с подстановочными знаками вызывают общую ошибку voodoo

Кто-нибудь знает, почему следующий код не компилируется? Ни add (), ни addAll () не работают. Удаление части «? Extends» заставляет все работать, но тогда я не смог бы добавлять подclassы Foo.

List list1 = new ArrayList(); List list2 = new ArrayList(); /* Won't compile */ list2.add( new Foo() ); //error 1 list1.addAll(list2); //error 2 

ошибка 1:

IntelliJ говорит:

 add(capture) in List cannot be applied to add(Foo) 

Компилятор говорит:

 cannot find symbol symbol : method addAll(java.util.List) location: interface java.util.List 

ошибка 2:

IntelliJ дает мне

 addAll(java.util.Collection<? extends capture>) in List cannot be applied to addAll(java.util.List<capture>) 

В то время как компилятор просто говорит

 cannot find symbol symbol : method addAll(java.util.List) location: interface java.util.List list1.addAll(list2); 

(Я предполагаю, что Bar и Baz оба являются подтипами Foo .)

List List означает список элементов некоторого типа, который является подтипом Foo, но мы не знаем, какой тип . Примерами таких списков могут быть ArrayList , LinkedList и ArrayList .

Поскольку мы не знаем, какой подтип является параметром типа, мы не можем помещать в него объекты Foo , ни объекты Bar ни Baz . Но мы все еще знаем, что параметр type является подтипом Foo , поэтому каждый элемент, который уже есть в списке (и который мы можем получить из списка), должен быть объектом Foo , поэтому мы можем использовать Foo f = list.get(0); и подобные вещи.

Такой список можно использовать только для элементов из списка, а не для добавления элементов вообще (кроме null , но я не знаю, разрешает ли это компилятор).

List с другой стороны, позволяет добавлять любой объект, который является объектом Foo и поскольку Bar и Baz являются подтипами Foo , все объекты Bar и Baz являются объектами Foo , поэтому их также можно добавить.

Помните PECS: продюсер продюсеров, Consumer Super .

Поскольку вы пытаетесь добавить элементы в list2, это потребитель и не может быть объявлен как List List . Но тогда вы используете list2 как продюсер, когда добавляете его в list1. Поэтому list2 является как производителем, так и потребителем и должен быть List .

list1, как чистый потребитель, может быть List List .

Это ошибки. Позволяет изменить ваш код, учитывая, что Bar и Baz являются двумя разными типами, расширяющими Foo :

 List list1 = new ArrayList(); List list2 = new ArrayList(); 

Если list1.add(new Foo()) разрешен, вы можете добавить экземпляры Foo в коллекцию, содержащую экземпляры Bar. Это объясняет первую ошибку.

Если list1.addAll(list2) разрешен, все экземпляры Baz в списке2 будут добавлены в список1, который содержит только экземпляры Bar. Это объясняет вторую ошибку.

Позвольте мне попытаться объяснить, в каком случае вам может понадобиться использовать .

Итак, скажем, у вас есть 2 classа:

 class Grand { private String name; public Grand(String name) { this.setName(name); } public Grand() { } public void setName(String name) { this.name = name; } } class Dad extends Grand { public Dad(String name) { this.setName(name); } public Dad() { } } 

И скажем, у вас есть 2 коллекции, каждая из которых содержит некоторые гранды и некоторые папы:

  List dads = new ArrayList<>(); dads.add(new Dad("Dad 1")); dads.add(new Dad("Dad 2")); dads.add(new Dad("Dad 3")); List grands = new ArrayList<>(); dads.add(new Dad("Grandpa 1")); dads.add(new Dad("Grandpa 2")); dads.add(new Dad("Grandpa 3")); 

Теперь давайте предположим, что мы хотим иметь коллекцию, которая будет содержать объекты Grand или Dad:

  List resultList; resultList = dads; // Error - Incompatable types List List resultList = grands;//Works fine 

Как мы можем избежать этого? Просто используйте подстановочный знак:

 List resultList; resultList = dads; // Works fine resultList = grands;//Works fine 

Обратите внимание, что вы не можете добавлять новые элементы в такую ​​(resultList) коллекцию. Для получения дополнительной информации вы можете прочитать о конкретизации подстановочных знаков и PECS в Java

Извините, возможно, я неправильно понял ваш вопрос, но, полагаю,

 public class Bar extends Foo{ } 

этот код:

 List list2 = new ArrayList() list2.add( new Bar() ); 

не создавайте никаких ошибок для меня.

Таким образом, удаление wild card позволяет добавлять подclassы Foo.