Непроверенное предупреждение о приведении с помощью Java Generics, параметра type и возвращенного списка - PullRequest
2 голосов
/ 24 сентября 2010

Этот код максимально упрощен из более сложной структуры классов.В реальном коде были подтипы типов Integer и Double, которые я здесь использую.

Я пытаюсь использовать Java Generics с параметром типа.Если пользователь запрашивает тип Number.class, мы хотим объединить список List<Integer> и список List<Double> в один список.

Пока работает код, я не могу получить доступ к непроверенному приведениюпредупреждение (см. тег TODO).Предупреждение:

Type safety: Unchecked cast from List<Integer> to Collection<? extends T>

Но, если я удалю приведение, я получу ошибку компиляции:

The method addAll(Collection<? extends T>) in the type List<T> is not applicable for the arguments (List<Integer>).

Мой код:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class Generics1 {

    static final List<Integer> intList = new ArrayList<Integer>(Arrays.asList(
        1, 2, 3, 4));
    static final List<Double> dblList = new ArrayList<Double>(Arrays.asList(
        1.1, 2.2, 3.3));

    public static <T extends Number> List<T> getObjects(Class<T> type) {
        List<T> outList = new ArrayList<T>();
        if (type == Number.class) {
            // user asked for everything
            // TODO: unchecked cast warnings here should be fixed
            outList.addAll((Collection<? extends T>) intList);
            outList.addAll((Collection<? extends T>) dblList);
        } else {
            // user asked for subtype of number
            if (Integer.class.isAssignableFrom(type)) for (Integer i : intList)
                if (type.isInstance(i)) {
                    T obj = type.cast(i);
                    outList.add(obj);
                }
            if (Double.class.isAssignableFrom(type)) for (Double d : dblList)
                if (type.isInstance(d)) {
                    T obj = type.cast(d);
                    outList.add(obj);
                }
        }
        return outList;
    }

    public static void main(String[] args) {
        System.out.println("HI!");
        System.out.println("integers: " + getObjects(Integer.class));
        System.out.println("doubles: " + getObjects(Double.class));
        System.out.println("numbers: " + getObjects(Number.class));
    }
}

Ответы [ 3 ]

0 голосов
/ 24 сентября 2010

(предыдущий ответ удален)

Вот способ сделать это с Guava:

@SuppressWarnings("unchecked")
public static <T> List<T> filterAndCollapse(final Class<T> type,
        Collection<?> a, Collection<?> b) {
    List combined = new ArrayList();
    Predicate<Object> filter = new Predicate<Object>() {

        public boolean apply(Object obj) {
            return type.isInstance(obj);
        }
    };
    combined.addAll(Collections2.filter(a, filter));
    combined.addAll(Collections2.filter(b, filter));
    return combined;
}
// ...
filter(Number.class, intList, dblList);

Редактировать: Полностью безопасный тип для сравнения. *Насколько мне известно, 1008 *

public static <T> List<T> filterAndCollapse(final Class<T> type,
        Collection<?> a, Collection<?> b) {
    List<T> combined = new ArrayList<T>();
    Predicate<Object> filter = new Predicate<Object>() {

        public boolean apply(Object obj) {
            return type.isInstance(obj);
        }
    };
    Function<Object, T> transform = new Function<Object, T>() {

        public T apply(Object obj) {
            return type.cast(obj);
        }
    };
    combined.addAll(Collections2.transform(Collections2.filter(a, filter),
        transform));
    combined.addAll(Collections2.transform(Collections2.filter(b, filter),
        transform));
    return combined;
}

К сожалению, нет способа фильтровать и преобразовывать в один шаг с Guava.

0 голосов
/ 25 сентября 2010
    (Class<T> type)
    List<T> outList = new ArrayList<T>();

    if (type == Number.class) {
        // obviously, T==Number here, though the compiler doesn't know that
        // so we do the cast. compiler will still warn. since the cast makes 
        // perfect sense and is obviously correct, we are ok with it.   
        List<Number> numList = (List<Number>)outList;
        numList.addAll( intList);
        numList.addAll( dblList);
    } else {

Лучшее решение, просто

for list in lists
  for item in list 
     if item instance of type
        add item to result
0 голосов
/ 24 сентября 2010

Вы можете добавить это к своему коду:

@SuppressWarnings("unchecked")

Вот еще один пост SO, который объясняет, что это означает: Что такое SuppressWarnings («unchecked»)в Java?

А вот еще один пример, который может быть полезен для преобразования ссылки: Как исправить "Выражение типа List требует неконтролируемого преобразования ... '?

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

...