如何删除通用列表类型?当我自己尝试时,会出现错误



我试图弄清楚以下方法是如何类型擦除的

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指出的那样,将这个问题标记为"什么是原始类型,我们为什么不应该使用它?"?,你不应该自己尝试删除类型。但了解它在做什么是有用的。

擦除发生在编译器的类型检查阶段之后。最终,它将产生您所写的内容,但类型检查是首先完成的。

最新更新