1

我们有通用类

SomeClass<T>{ }

我们可以写一行:

SomeClass s= new SomeClass<String>();

没关系,因为原始类型是泛型类型的超类型。但

SomeClass<String> s= new SomeClass();

是正确的。为什么是正确的?我认为类型擦除是在类型检查之前,但这是错误的。

从黑客指南到 Javac

当使用默认编译策略调用 Java 编译器时,它会执行以下步骤:

  1. parse:读取一组 *.java 源文件并将生成的令牌序列映射到 AST 节点。
  2. enter:将定义的符号输入到符号表中。
  3. 处理注释:如果请求,处理在指定编译单元中找到的注释。
  4. 属性:属性语法树。此步骤包括名称解析、类型检查和常量折叠。
  5. flow:对上一步中的树执行数据流分析。这包括检查分配和可达性。
  6. desugar:重写 AST 并翻译掉一些语法糖。
  7. generate:生成源文件或类文件。

泛型是语法糖,因此类型擦除在第 6 遍调用,在类型检查之后,在第 4 遍调用。我很困惑。

4

1 回答 1

0

类型参数肯定参与类型检查;否则它将毫无意义(即不比原始类型更好)。

生成隐式转换也需要该信息,因此它可以在您的第 7 步中继续存在,并在技术上作为调试符号运行到运行时。但是,只有擦除将参与运行时类型转换检查(出于明显的向后兼容性原因)。尽管如此,如果您的通用代码可以完全静态检查,它可以与非类型擦除语言中的通用程序一样强大。

当你分配SomeClass给 时SomeClass<String>,编译器会给你一个关于原始类型使用的警告。此时,您的程序显然不再安全。

于 2013-11-02T09:50:27.803 回答