有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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) 个答案

  1. # 1 楼答案

    Object[] toArray() Returns an array containing all of the elements in this list in proper sequence (from first to last element).

    我们正在将其强制转换为E[]推断泛型,因此强制转换未经检查,因为jvm不知道E将是什么类型,因此警告无效

    例如,E是字符串类型(就像您在代码中所说的那样)。我们试图将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;
    }
    

    这将创建类强制转换异常

  2. # 2 楼答案

    编译时不能保证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[]数组,因此在返回的泛型类型隐式转换为String[]之后,您将在main方法中获得ClassCastException

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

  3. # 3 楼答案

    这里使用的list.toArray习惯用法不是由List的参数化类型数组参数化的,因此它返回Object[]

    例如,使用List<String> str,可以不强制转换地调用:String[] foo = str.toArray(new String[str.size()]);

    这里的问题是,由于Java泛型的设计,您永远无法初始化new E[],因此必须强制转换到(E[])

    我看不到这会像现在这样抛出{}

    正如其他人提到的,“修饰性”解决方案是在toArray调用之前添加@SuppressWarnings("unchecked"),这将抑制警告

  4. # 4 楼答案

    你的演员阵容没有问题,但是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;
    }