我试图弄清楚以下方法是如何类型擦除的
public class Util {
public static <T extends Number> int sum(List<T>list){
int sum=0;
for(Number n:list){
sum+=n.intValue();
}
return sum;
}
}
我读到类型参数被替换为它的第一个绑定。所以我尝试了一下,但出现了一个错误:
public static int sum3(List list){
int sum=0;
for(Number n:list){ <- Type mismatch: cannot convert from element type Object to Number
sum+=n.intValue();
}
return sum;
}
您的第二个代码实际上不是类型擦除后的等效代码。不可能,因为正如您所发现的,增强的for循环不会编译。
如果您查阅语言规范,它显示了增强的for循环的等效基本for循环:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
{VariableModifier} TargetType Identifier =
(TargetType) #i.next();
Statement
}
实际上,这就是执行的内容:增强的for循环只是基本for循环的语法糖,它看起来像这样。
因此,编译器对您的第一个代码所做的第一件事就是将其"降级"为:
public static <T extends Number> int sum(List<T>list){
int sum=0;
for (Iterator<Number> i = list.iterator(); i.hasNext(); ) {
Number n = (Number) i.next();
sum += n.intValue();
}
return sum;
}
然后,当应用类型擦除时,它将重写为:
public static int sum(List list){
int sum=0;
for (Iterator i = list.iterator(); i.hasNext(); ) {
Number n = (Number) i.next();
sum += n.intValue();
}
return sum;
}
请注意,这里唯一不同的是,在第一种情况下,i.next()
是Number
,因此不需要强制转换;但第二个是Object
(因为原始迭代器),所以强制转换是必要的。
这种形式的类型擦除代码编译。事实上,如果您尝试反编译这个版本的代码,您会发现它的字节码与OP问题中的第一个代码相同。
当然,正如Sotirios指出的那样,将这个问题标记为"什么是原始类型,我们为什么不应该使用它?"?,你不应该自己尝试删除类型。但了解它在做什么是有用的。
擦除发生在编译器的类型检查阶段之后。最终,它将产生您所写的内容,但类型检查是首先完成的。