9.早期(编译期) 优化

1.概述
Java语言的“编译期”,可能是指一个前端编译器把*.java文件转变成*.class文件的过程; 也可能是指虚拟机的后端运行期编译器(JIT编译器, Just In Time Compiler) 把字节码转变成机器码的过程; 还可能是指使用静态提前编译器(AOT编译器, Ahead Of Time Compiler) 直接把*.java文件编译成本地机器代码的过程。
前端编译器: Sun的Javac、 Eclipse JDT中的增量式编译器(ECJ)。
JIT编译器: HotSpot VM的C1、 C2编译器。
AOT编译器: GNU Compiler for the Java(GCJ)、 Excelsior JET。
Java中即时编译器在运行期的优化过程对于程序运行来说更重要, 而前端编译器在编译期的优化过程对于程序编码来说关系更加密切。
2.Javac编译器
编译过程大致可以分为3个过程:
解析与填充符号表过程。
插入式注解处理器的注解处理过程。
分析与字节码生成过程。
9.早期(编译期) 优化
9.早期(编译期) 优化
2.1 解析与填充符号表
解析步骤由图10-5中的parseFiles() 方法(图10-5中的过程1.1) 完成, 解析步骤包括了经典程序编译原理中的词法分析和语法分析两个过程。
A.词法、 语法分析
词法分析是将源代码的字符流转变为标记(Token) 集合, 单个字符是程序编写过程的最小元素, 而标记则是编译过程的最小元素, 关键字、 变量名、 字面量、 运算符都可以成为标记。
语法分析是根据Token序列构造抽象语法树的过程, 抽象语法树(Abstract Syntax Tree,AST) 是一种用来描述程序代码语法结构的树形表示方式, 语法树的每一个节点都代表着程序代码中的一个语法结构(Construct)。
B.填充符号表
完成了语法分析和词法分析之后, 下一步就是填充符号表的过程, 也就是图10-5中enterTrees() 方法所做的事情。 符号表(Symbol Table) 是由一组符号地址和符号信息构成的表格。
2.2 注解处理器
提供了一组插入式注解处理器的标准API在编译期间对注解进行处理, 我们可以把它看做是一组编译器的插件, 在这些插件里面, 可以读取、 修改、 添加抽象语法树中的任意元素。
2.3 语义分析与字节码生成
语法分析之后, 编译器获得了程序代码的抽象语法树表示, 语法树能表示一个结构正确的源程序的抽象, 但无法保证源程序是符合逻辑的。 而语义分析的主要任务是对结构上正确的源程序进行上下文有关性质的审查, 如进行类型审查。
A.标注检查
Javac的编译过程中, 语义分析过程分为标注检查以及数据及控制流分析两个步骤, 分别由图10-5中所示的attribute() 和flow() 方法(分别对应图10-5中的过程3.1和过程3.2) 完成。
标注检查步骤检查的内容包括诸如变量使用前是否已被声明、 变量与赋值之间的数据类型是否能够匹配等。 在标注检查步骤中, 还有一个重要的动作称为常量折叠。
B.数据及控制流分析
数据及控制流分析是对程序上下文逻辑更进一步的验证, 它可以检查出诸如程序局部变量在使用前是否有赋值、 方法的每条路径是否都有返回值、 是否所有的受查异常都被正确处理了等问题。
C.解语法糖
语法糖(Syntactic Sugar) , 也称糖衣语法,指在计算机语言中添加的某种语法, 这种语法对语言的功能并没有影响, 但是更方便程序员使用。 通常来说, 使用语法糖能够增加程序的可读性, 从而减少程序代码出错的机会。
D.字节码生成
字节码生成是Javac编译过程的最后一个阶段, 在Javac源码里面com.sun.tools.javac.jvm.Gen类来完成。
3. Java语法糖
3.1 泛型与类型擦除
泛型是JDK 1.5的一项新增特性, 它的本质是参数化类型(Parametersized Type) 的应用, 也就是说所操作的数据类型被指定为一个参数。 这种参数类型可以用在类、 接口和方法的创建中, 分别称为泛型类、 泛型接口和泛型方法。
Java语言中的泛型只在程序源码中存在, 在编译后的字节码文件中, 就已经替换为原来的原生类型(Raw Type, 也称为裸类型) 了, 并且在相应的地方插入了强制转型代码,Java语言中的泛型实现方法称为类型擦除, 基于这种方法实现的泛型称为伪泛型。
3.2 自动装箱、 拆箱与遍历循环
9.早期(编译期) 优化
3.3 条件编译
编译器并非一个个地编译Java文件, 而是将所有编译单元的语法树顶级节点输入到待处理列表后再进行编译, 因此各个文件之间能够互相提供符号信息。
Java语言中条件编译的实现,根据布尔常量值的真假, 编译器将会把分支中不成立的代码块消除掉, 这一工作将在编译器解除语法糖阶段(com.sun.tools.javac.comp.Lower类中) 完成。 它只能实现语句基本块(Block) 级别的条件编译, 而没有办法实现根据条件调整整个Java类的结构。