10.2 Javac编译器
10.2.2 解析与填充符号表
1、 词法、语法分析
词法分析是将源代码的字符流转变为标记(Token)集合,单个字符是程序萹蓄过程的最小元素,而标记时编译过程的最小元素,关键字、变量名、字面量、运算符都可以成为标记。
语法分析是根据Token序列构造抽象语法树的过程,
抽象语法树是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点都代表着程序代码中的一个语法结构,例如包、类型、修饰符、运算符、接口、返回值甚至代码注释都是可以是一个语法结构
2、填充符号表
符号表是由一组符号地址和符号信息构成的表格。
符号表中所登记信息在编译的不同阶段都要用到。在语义分析中,符号表所登记的内容将用于语义检查和产生中间代码。在目标代码生成阶段,当对符号进行地址分配时,符号表是地址分配的依据。
10.2.3 注解处理器
可以看做是一组编译器的插件,可以读取、修改、添加抽象语法树中的任意元素。
如果这些插件在处理注解期间对语法树进行了修改,编译器将回到解析及填充符号表的过程重新处理,直到所有插入式注解处理器都没有再对语法树进行修改为止。
10.2.4 语义分析与字节码生成
语法树能表示一个结构正确的源程序的抽象,但无法保证源程序是符合逻辑的。
语义分析的主要任务是对结构上正确的源程序进行上下文有关性质的审查。
1、标注检查
标注检查步骤检查的内容包括诸如变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配等。
以及常量折叠:
//对于如下代码,语法树上仍能看到字面量 1 和 2 以及 +
//但在常量折叠后,它们将会被折叠为字面量 3
int a = 1 + 2;
2、数据及控制流分析
对程序上下文逻辑更进一步的验证。
能够检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理了等问题。
3、解语法糖
Java中最常用的语法糖主要是泛型、变长参数、自动装箱/拆箱等,JVM运行时不支持这些语法,它们在编译阶段还原回简单的基础语法结构
4、字节码生成
字节码生成阶段不仅仅是把前面各个步骤所生成的信息转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。
例如上文中多次提到的实例构造器<init>()和类构造器<clinit>()就是在这个阶段添加到语法树中。
10.3 Java语法糖的味道
10.3.1 泛型与类型擦除
泛型本质是参数化类型的应用,也就是说所操作的数据类型被指定为一个参数。
Java中的泛型只在源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(List<E>),并在相应地方插入了强制转型代码。
10.3.2 自动装箱、拆箱与遍历循环
自动装箱、拆箱在编译之后被转化成了对应的包装和还原方法
遍历循环则把代码还原成了迭代器的实现
变长参数,在调用的时候变成了一个数组类型的参数
10.3.3 条件编译
根据布尔常量值的真假,编译器会把分支中不成立的代码块消除掉,这一工作将在编译器解除语法糖阶段完成。