Преобразование не общего типа списка в тип общего списка в Java 1.5

17

У меня есть список, который, как гарантируется, содержит только один объект типа. Это создается некоторым базовым кодом в библиотеке, которую я не могу обновить. Я хочу создать List & lt; ObjectType & gt; на основе входящего объекта List, чтобы мой код вызова говорил с List & lt; ObjectType & gt;.

Каков наилучший способ преобразования списка (или любой другой коллекции объектов) в List & lt; ObjectType & gt;.

    
задан Shaun F 30.09.2009 в 17:43
источник

5 ответов

14

При взаимодействии с устаревшим кодом, который не задает параметры типа для общих типов, используйте шаблон. Например, предположим, что вы вызываете метод в старой библиотеке, которая просто возвращает raw Collection :

Collection getItems();

В вашем коде присвойте результат переменной, объявленной с помощью подстановочного знака:

Collection<?> items = widget.getItems();

Таким образом, вы сохраняете безопасность типов, чтобы вы не получали никаких предупреждений.

Устаревший код может указывать (в комментарии, скорее всего), какие должны быть общие параметры. Например:

/**
 * @return the items, as a Collection of {@link Item} instances.
 */
Collection getItems();

В этом случае у вас есть выбор. Вы можете привести результат к Collection<Item> , но если вы это сделаете, вы полагаетесь на 100% на стороннюю библиотеку и отбрасываете уверенность в типах Java: какие-либо ClassCastException поднятый во время выполнения, произойдет прямо при явном приведении.

Что делать, если вы не полностью доверяете сторонней библиотеке, но все равно нужно создать Collection<Item> ? Затем создайте новую коллекцию и добавьте содержимое после их добавления к ожидаемому типу. Таким образом, если в библиотеке есть ошибка, вы сразу узнаете об этом, вместо того, чтобы иметь некоторый код далеко и намного позже таинственно взорвали ClassCastException .

Например:

Collection<?> tmp = widget.getItems();
Collection<Item> items = new ArrayList<Item>(tmp.size());
for (Object o : tmp)
  items.add((Item) o); /* Any type error will be discovered here! */

В случае, когда параметр типа неизвестен во время компиляции, вы можете использовать проверенные фабрикой коллекции класса Collections .

    
ответ дан erickson 30.09.2009 в 17:53
  • Проблема заключается в том, что на самом деле вы ничего не делаете, кроме как отключить предупреждения типа «raw type». Преобразование в generics подразумевало бы использование его преимуществ! –  Andrzej Doyle 30.09.2009 в 17:58
  • В чем преимущество дженериков? Это не значит, что ваш код выглядит красиво и требует меньше ввода текста! Это так: ваш код гарантированно безопасен по типу, если он компилируется без предупреждений. Вот и все. Когда вы игнорируете или подавляете предупреждения, вы можете вообще не использовать дженерики, потому что все, что вы делаете, это создание ситуаций, когда код без оператора трансляции загадочно вызывает ClassCastException. –  erickson 30.09.2009 в 18:07
11

Вы можете просто перечислить список:

  List raw = new ArrayList();
  List<String> generic = (List<String>) raw;
    
ответ дан daveb 30.09.2009 в 17:45
  • Если список действительно гарантированно удерживает один тип элемента, это хороший ответ. –  Michael Myers♦ 30.09.2009 в 17:55
  • Это большой «если». Это очень зависит от контекста. –  erickson 30.09.2009 в 18:11
  • Я могу гарантировать, что список будет содержать один тип элемента. Это был код, написанный в предварительных дженериках Java 1.4. –  Shaun F 30.09.2009 в 19:35
  • Это не безопасно для типов вообще, потому что для этого требуется, чтобы список был однородным; что все объекты в списке одного типа. Если в списке содержится объект другого типа, чем другие, программа может позже вызывать исключение ClassCastException, и это исключение не укажет вам, где был создан список. –  Derek Mahar 20.08.2010 в 20:31
  • Во избежание ситуации, описанной в моем предыдущем комментарии, компилятор Eclipse Java, когда он сталкивается с приведением из устаревшего списка в общий список, генерирует предупреждение «Тип безопасности: выражение типа List needs unchecked conversion, чтобы соответствовать List <String> ". Программисты, которые игнорируют эти предупреждения во время компиляции, делают это на свой страх и риск во время выполнения. –  Derek Mahar 20.08.2010 в 20:33
1

Попробуйте следующее:

List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray());

Но помните, что это создаст список фиксированной длины. Если вы попытаетесь добавить или удалить элемент из этого списка, он выдает ошибку. Поэтому всегда будьте осторожны при использовании Arrays.asList() .     

ответ дан sluimers 16.01.2012 в 16:59
1

Самый лучший и безопасный способ - использовать метод java.util.Collections 'checkedList (Список списка, Тип класса)'

С помощью этого метода все элементы в вашем старом списке будут проверены как можно раньше.

    
ответ дан nanda 12.01.2010 в 17:31
  • Не провереноList в Java 5 применяется только к новым (и пустым) общим спискам? Предлагаете ли вы использовать не общий шаблон checkedList до Java 5? Эта устаревшая форма не будет конвертироваться в общий список. –  Derek Mahar 20.08.2010 в 21:12
0

Если вы просто нажмете на List<T> в любом старом месте, вы получите предупреждение о неконтролируемом компиляторе. Мы решили это, переместив его к утилитарному методу.

public class Lists {
    @SuppressWarnings({"unchecked"})
    public static <T> List<T> cast(List<?> list) {
        return (List<T>) list;
    }
}

Теперь вызывающий абонент не получает предупреждения, например:

for (Element child : Lists.<Element>cast(parent.getChildren())) {
    // ...
}

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

    
ответ дан Trejkaz 18.06.2010 в 03:58