这里有以下代码:
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
将失败。