Javac编译器与语法糖
Javac编译过程大致分为3个过程:
- 解析与填充符号表
- 插入式注解器的注解处理过程
- 分析与字节码生成过程
###解析与填充符号表
- 词法、语法分析:词法分析是将源代码的字符流转变为标记(Token)集合。 语法分析是根据Token序列来构造抽象语法树的过程。经过这个步骤后,编译器就基本不会再对源码文件进行操作了,后续的操作都建立在抽象语法树之上。
- 填充符号表:符号表是由一组符号地址和符号信息构成的表格。符号表中所登记的信息在编译的不同阶段都要用到,在语义分析(后面的步骤)中,符号表所登记的内容将用于语义检查和产生中间代码,在目标代码生成阶段,党对符号名进行地址分配时,符号表是地址分配的依据。
###注解处理器
注解处理器是一组编译器额插件,可以读取、修改、添加抽象语法书上的任意元素。如果这些插件在处理注解期间对语法书进行了修改,编译器将回到解析及符号填充表过程重新处理。
注解处理器主要有三个用途。一是定义编译规则,并检查被编译的源文件。二是修改已有源代码。三是生成新的源代码。其中,第二种涉及了 Java 编译器的内部 API,因此并不推荐。第三种较为常见,是 OpenJDK 工具 jcstress,以及 JMH 生成测试代码的方式。
###语义分析与字节码生成
- 标注检查:标注检查包括变量使用前是否被声明,变量与赋值之间的数据类型能否匹配等。
- 数据及控制流分析:对程序的逻辑更进一步验证,可以检查局部变量在使用前是否被赋值,方法的每条路径是否都有返回值,受检查异常都有正确处理等问题
- 解语法糖:对于虚拟机不支持的如泛型,自动装箱/拆箱在编译期间还原会简单的基础语法结果。
- 字节码生成:字节码生成阶段不仅仅是把前面各个步骤所生成的信息转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。 实例构造器()方法和类构造器()方法就是在这个阶段添加到语法树之中的(这里的实例构造器并不是指默认的构造函数,而是指我们自己重载的构造函数,如果用户代码中没有提供任何构造函数,那编译器会自动添加一个没有参数、访问权限与当前类一致的默认构造函数,这个工作在填充符号表阶段就已经完成了)。经过对语法数的遍历和调整之后生成最终的Class文件。
##Java语法糖
- 泛型擦除:Java语言中的泛型只在程序源代码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型,并且在相应的地方插入强制转型代码。
- 自动装箱、拆箱:自动装箱、拆箱在编译之后被转化成了对象的包装和还原方法。如果Integer.valueOf()与Integer.intValue()。
- 遍历循环:遍历循环则把代码还原成了迭代器的实现
- 变长参数:变长参数在调用的时候变成了一个数组类型的参数