Generics (Список) печатать вопрос - PullRequest
3 голосов
/ 25 июня 2010

Я пытаюсь использовать общую технику для создания объектов из Xml. (XML унаследован, поэтому, хотя для этого уже есть библиотеки, казалось, быстрее написать это сам.)

Я не понимаю жалобу компилятора на общее использование. Пример кода:

public void createObjects() {
  List<Object1> objectOnes = new ArrayList<Object1>();
  List<Object2> objectTwos = new ArrayList<Object2>();

  parseObjectsToList("XmlElement1", objectOnes);
  parseObjectsToList("XmlElement2", objectTwos);
}

private void parseObjectsToList(String xmlTag, List<? extends Object> targetList) {
   // read Xml and create object using reflection
   Object newObj = createObjectFromXml(xmlTag);
   targetList.add(newObj)  

/* compiler complains: "The method add(capture#2-of ? extends Object) in the type List<capture#2-of ? extends Object> is not applicable for the arguments (Object)" 
*/

/* If I change method signature to parseObjectsToList(String xmlTag, List targetList)
it works fine, but generates compiler warning about raw type */

}

Спасибо за просвещение по этому вопросу!

Ответы [ 4 ]

4 голосов
/ 25 июня 2010

Проблема, с которой вы сталкиваетесь, заключается в том, что с заданным ограниченным символом подстановки вы не сможете добавить какой-либо элемент в коллекцию. Из этого урока :

List<? extends Shape > является примером ограниченного символа подстановки. ? обозначает неизвестный тип, точно так же как символы подстановки, которые мы видели ранее. Однако в этом случае мы знаем, что этот неизвестный тип на самом деле является подтипом Shape. (Примечание: это может быть сама форма или некоторый подкласс; ей не нужно буквально расширять форму.) Мы говорим, что форма - это верхняя граница подстановочного знака.

Как обычно, за гибкость использования подстановочных знаков приходится платить цену. Эта цена состоит в том, что теперь запрещено писать фигуры в теле метода

2 голосов
/ 25 июня 2010

Все подстановочные знаки означают, что фактический параметр типа T из List, который вы передаете в качестве второго аргумента parseObjectsToList, будет подтипом Object. Это НЕ означает, что один и тот же List будет параметризован разными типами.

Итак, теперь у вас есть List<T> (называемый targetList), и вы пытаетесь позвонить targetList.add(Object). Это незаконно, потому что Object не обязательно является подтипом T.

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

1 голос
/ 25 июня 2010

Подумайте о том, что вы просите, чтобы компилятор сделал:

  1. Учитывая список "чего-то, что является подтипом Object
  2. Позвольте мне вставить Objectв него

Это не имеет смысла. Предположим, ваш список представляет собой список Integer. Предположим, что createObjectFromXml возвращает String. Не имеет смысла разрешать вставкуString в список, набранный для Integers.

Итак, вы можете либо сделать свой список List<Object>, либо найти способ заставить createObjectFromXml возвращать определенный тип, который вы можетезатем привяжите к типу вашего списка.

1 голос
/ 25 июня 2010

Использование List<Object> будет работать, но вы, возможно, захотите сохранить ваши более точные набранные List<Object1> и List<Object2> для обеспечения безопасности типов в других местах.В этом случае вам необходимо проверить тип каждого объекта перед добавлением его в List.

private void parseObjectsToList(String tag, List<T> list, Class<? extends T> c) {
   // read Xml and create object using reflection
   Object newObj = createObjectFromXml(tag);
   list.add(c.cast(newObj))  ;
}

Операция cast() является отражающим эквивалентом оператора статического приведения: (T) newObj

Использование измененного метода будет выглядеть примерно так:

parseObjectsToList("XmlElement1", objectOnes, Object1.class);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...