原始类型和子类型

时间:2013-11-02 08:41:42

标签: java compiler-construction raw-types

我们有通用类

SomeClass<T>{ }

我们可以写下这一行:

SomeClass s= new SomeClass<String>();

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

SomeClass<String> s= new SomeClass();

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

从Hacker's Guide to Javac

  

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

     
      
  1. 解析:读取一组* .java源文件并映射生成的令牌   顺序进入AST-Nodes。
  2.   
  3. 输入:将定义的符号输入符号表。
  4.   
  5. 处理注释:如果已请求,则处理在中找到的注释   指定的编译单元。
  6.   
  7. 属性:属性语法树。此步骤包括名称   分辨率,类型检查和常数折叠。
  8.   
  9. flow:对上一步中的树执行数据分析。   这包括检查分配和可达性。
  10.   
  11. desugar:重写AST并翻译一些语法糖。
  12.   
  13. 生成:生成源文件或类文件。
  14.   

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

1 个答案:

答案 0 :(得分:0)

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

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

当您将SomeClass分配给SomeClass<String>时,编译器会向您发出有关原始类型使用的警告。此时,您的程序显然已不再安全。