未经检查的演员阵容有什么问题?

时间:2015-07-01 08:51:19

标签: java

我正在阅读J. Bloch的有效Java,现在我在数组与列表部分。以下是他提供的未经检查演员的示例:

interface Function<T> {
    T apply(T arg1, T arg2);
}

public class Main{
    public static void main( String[] args ){
        Function<String> f = null;
        List<String> str = Arrays.asList("asd");
        //staff
        reduce(str, f, ""); //E's deduced to String. Where is type-unsafe?
    }
    static <E> E reduce(List<E> list, Function<E> f, E initVal) {
        E[] snapshot = (E[]) list.toArray(); // Unchecked cast
        E result = initVal;
        for (E e : snapshot)
            result = f.apply(result, e);
        return result;  
    }
}

他说该方法不是类型安全的,我们可以轻松获得ClassCastException。但我不知道怎么做。哪里是类型不安全的,类型变量E将总是被推导为适当的类型,所以我们不担心类 - 强制执行。

你不能举一个抛出ClassCastException的例子吗?

4 个答案:

答案 0 :(得分:13)

没有编译时保证list.toArray()将返回E[]类型的数组。而且它几乎总是返回一个类型为Object[]的数组。因此,根据此数组的后续用法,您可能会有ClassCastException。例如,请考虑以下代码:

public static void main( String[] args ){
    List<String> str = Collections.singletonList("asd");
    String[] array = test(str);
}

static <E> E[] test(List<E> list) {
    E[] snapshot = (E[]) list.toArray(); // Unchecked cast
    return snapshot;
}

这里返回此E[]数组,接收方期望返回String[]数组。但实际上它是Object[]数组,因此在返回的泛型类型隐式转换为ClassCastException后,您将在main方法中获得String[]

在您的代码中,您可以确保以安全的方式使用阵列。但是编译器不够聪明,不能进行这种分析,所以它只是警告你。

答案 1 :(得分:4)

您在此处使用的list.toArray惯用语不是由List参数化类型的数组参数化,因此它返回Object[]

例如,使用List<String> str,您可以调用:String[] foo = str.toArray(new String[str.size()]);而不进行投射。

这里的问题是,由于Java泛型&#39;设计,你永远不能初始化new E[],因此你必须强制转换为(E[])

我无法看到这样抛出ClassCastException

正如其他人所说,&#34;化妆品&#34;解决方法是在@SuppressWarnings("unchecked")调用之前添加toArray,这将取消警告。

答案 2 :(得分:4)

  

Object [] toArray()返回包含所有元素的数组   此列表按正确顺序排列(从第一个元素到最后一个元素)。

我们将这个转换为E []推断泛型,因此转换是未选中的,因为jvm不知道E将是什么类型的警告。

比如说,E是String类型(如代码所示)。我们正在尝试将Object []转换为String [],对于其他一些情况,它很可能是Object []到Integer []。这个有效性不能在编译/运行时由jvm测试,所以问题。

 public static void main( String[] args ){
    List<String> str = Arrays.asList("asf");
    //staff

    System.out.println(reduce(str, 2)); //E's deduced to String. Where is type-unsafe?
}
static <E, T> E reduce(List<E> list, T initVal) {
    Object snapshot = list.size(); // Unchecked cast   
    return (E) snapshot;
}

这将创建类强制转换异常。

答案 3 :(得分:3)

您的演员阵容没有任何问题,但Java Generics

static <E> E reduce(List<E> list, Function<E> f, E initVal) {
    @SuppressWarnings({"unchecked"}) //nevermind
    E[] snapshot = (E[]) list.toArray(); //Unchecked cast
    E result = initVal;
    for (E e : snapshot)
        result = f.apply(result, e);
    return result;
}