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
的例子吗
# 1 楼答案
我们正在将其强制转换为E[]推断泛型,因此强制转换未经检查,因为jvm不知道E将是什么类型,因此警告无效
例如,E是字符串类型(就像您在代码中所说的那样)。我们试图将Object[]转换为String[],在其他情况下,它很可能是Object[]转换为Integer[]。jvm无法在编译/运行时测试这种有效性,因此问题很严重
这将创建类强制转换异常
# 2 楼答案
编译时不能保证
list.toArray()
将返回类型为E[]
的数组。此外,它几乎总是返回类型为Object[]
的数组。因此,根据该数组的以后使用情况,您可能会有一个ClassCastException
。例如,考虑下面的代码:这里返回这个
E[]
数组,接收方希望返回String[]
数组。但实际上它是Object[]
数组,因此在返回的泛型类型隐式转换为String[]
之后,您将在main
方法中获得ClassCastException
在您的代码中,您可以确保以安全的方式使用数组。但编译器不够聪明,无法进行这种分析,所以它只是警告您
# 3 楼答案
这里使用的
list.toArray
习惯用法不是由List
的参数化类型数组参数化的,因此它返回Object[]
例如,使用
List<String> str
,可以不强制转换地调用:String[] foo = str.toArray(new String[str.size()]);
这里的问题是,由于Java泛型的设计,您永远无法初始化
new E[]
,因此必须强制转换到(E[])
我看不到这会像现在这样抛出{}
正如其他人提到的,“修饰性”解决方案是在
toArray
调用之前添加@SuppressWarnings("unchecked")
,这将抑制警告# 4 楼答案
你的演员阵容没有问题,但是Java Generics: