【问题标题】:How is a generic list type erased? When I try it myself, it gives an error如何擦除通用列表类型?当我自己尝试时,它给出了一个错误
【发布时间】:2017-02-09 16:00:22
【问题描述】:

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

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;
}

【问题讨论】:

  • @Tunaki 那个骗子根本没有回答 OP 的问题。
  • @Andy 在 for-each 循环中使用原始列表不是同样的问题吗?在链接的问题中,他们有for (String s : perms) {,其中permsList,这也是OP 在这里的内容。
  • @Tunaki 但 OP 专门询问“如何删除以下方法的类型”。骗子基本上说“不要使用原始类型”——这当然是个好建议——但没有提供 OP 显然想知道的内容。
  • @Andy 好的,我明白你的意思了。我找到了this one(也许是this one)。如果您认为他们完全回答了这个问题,请随时重新关闭。
  • @Tunaki 对两者都没有 - 第一个只是关于方法签名(OP 也在询问方法主体);第二个是简单地询问为什么原始集合作为对象迭代(这与您之前的欺骗基本相同)。我认为 OP 正在询问如何为他的方法编写等效的类型擦除代码 - 请参阅我的答案。

标签: java generics


【解决方案1】:

您的第二个代码实际上不是类型擦除后的等效代码。不可能,因为正如您所发现的,增强的 for 循环不会编译。

如果您咨询language spec,它会显示等效的基本 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 通过将问题标记为 What is a raw type and why shouldn't we use it? 的欺骗所指出的那样,您不应该尝试自己进行类型擦除。但是知道它在做什么很有用。

【讨论】:

  • 这是我缺少的数字演员,因为 foreach 循环。
  • @ericj 这是您缺少的句法脱糖,然后演员。您不能使用增强的 for 循环应用强制转换。
  • 是的,我明白了。非常感谢。
  • 我检查了字节码。确实,它们是相同的。
【解决方案2】:

擦除发生在编译器的类型检查阶段之后。 最终,它会产生你写的,但类型检查是先完成的。

【讨论】:

  • @ericj 你读过答案吗?这里的关键字是最终
猜你喜欢
  • 1970-01-01
  • 2020-11-12
  • 2023-04-06
  • 1970-01-01
  • 2018-12-12
  • 2022-01-14
  • 2020-02-28
  • 1970-01-01
  • 2019-09-22
相关资源
最近更新 更多