这里有以下代码:

public final class Generics {
    private Generics() {}

    public static <T> T unchecked(Object obj) {
        return (T)obj; //unchecked cast warning
    }

    public static void main(String[] args) {
        //correct
        ArrayList<String> str = new ArrayList<String>();
        str.add("Hello");
        str.add("World");
        System.out.println(str);

        //"correct" - not type safe at all but due to type erasure this is almost legal
        ArrayList<Object> obj = Generics.<ArrayList<Object>>unchecked(str);
        obj.add(1);
        System.out.println(obj);

        //obviously wrong but still compiles (ClassCastException at runtime)
        Exception except = Generics.<Exception>unchecked(str);
        System.out.println(except);
    }
}


通常,形式为ArrayList<Object> obj = (ArrayList<Object>)str的强制转换将是致命的编译错误,因为这将违反使用该列表的预期。 (您可以将非字符串的对象插入仅字符串列表中)

在这种情况下,“未经检查”的警告是什么?unchecked()方法的使用与直接转换引用有何不同?如何绕过编译器的类型检查?

最佳答案

在这种情况下,“未选中”警告是什么


未检查的强制类型转换只是在字节码中实际上不会导致checkcast指令的强制类型转换。

public static <T> T unchecked(Object obj) {
    return (T)obj; //unchecked cast warning
}


在这里,这是未经检查的强制转换,因为T的擦除是Object,因此实际上是无操作的,因为obj已经是Object

但有害的是,在呼叫站点上插入了一个选中的强制转换:

Exception except = Generics.<Exception>unchecked(str);
               // ^ cast here!


擦除后,有效执行的代码为:

Exception except = (Exception) Generics.unchecked(str);


并且以ClassCastException失败。但是您不会对此有所警告,因为该方法的返回类型表明这将是安全的,因此编译器相信它在调用站点是安全的。

在呼叫站点无法知道unchecked方法正在做危险的事情。实际上,唯一可以做的安全的操作就是返回null。但是编译器不会考虑是否正在执行此操作:它只是将unchecked方法的声明以实际值作为准绳。


  unchecked()方法的使用与直接转换引用有何不同?


不是,真的。唯一的区别是您是通过Object隐式转换的。因此,虽然无法编译:

Exception except = (Exception) str;


这样做:

Exception except = (Exception) (Object) str;


并且在编译时使用相同的ClassCastException将失败。

10-07 16:56
查看更多