【问题标题】:Unchecked cast warning with Java Generics, type parameter, and returned list带有 Java 泛型、类型参数和返回列表的未经检查的强制转换警告
【发布时间】:2014-05-01 17:14:57
【问题描述】:

此代码已从更复杂的类结构中尽可能地简化。在实际代码中,我在这里使用了 Integer 和 Double 类型的子类型。

我正在尝试使用带有类型参数的 Java 泛型。如果用户请求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));
    }
}

【问题讨论】:

  • SuppressWarnings("unchecked") 够用吗?
  • 我忘了说,我编辑了这篇文章,将泛型放在代码块中的错误消息中,这样你就可以看到正在使用的泛型类型。
  • 感谢您编辑帖子。
  • 附注压制警告是作弊,因为我希望有一个优雅的解决方案,对不起!

标签: java generics type-parameter


【解决方案1】:

您可以将其添加到您的代码中:

@SuppressWarnings("unchecked")

这是另一个 SO 帖子,解释了“什么”的含义:What is SuppressWarnings ("unchecked") in Java?

这是另一个处理链接转换的可能有用的方法:How do I fix "The expression of type List needs unchecked conversion...'?

尽管通过一些重新编码,您可能会使警告完全消失,并且不需要被抑制。

【讨论】:

    【解决方案2】:
        (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
    

    【讨论】:

    • 是的,我真的可以使用 add(),因为 addAll() 是我收到编译器警告的地方。如果对于如何使用 addAll() 抑制警告没有更好的建议,我将重构代码以支持 add()。
    【解决方案3】:

    (之前的答案已删除)

    这是使用 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);
    

    编辑:完全类型安全的比较方式。

    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 一步过滤和转换。

    【讨论】:

    • @nanda:是的,原因是过滤器不会将项目转换为正确的类型。你可以这样做,但它需要一个额外的转换,这是运行时开销,因为这只是一个本地原始类型。我会将另一个添加回去进行比较。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    相关资源
    最近更新 更多