优化分为编译期优化和运行期优化,前者着重编码优化(语法糖),后者着重运行效率。语法糖syntactic sugar是指在计算机语言中添加某种语法,对语言的功能没有影响,但是更方便程序员使用,增加代码可读性。
一、javac的编译过程
1. 解析和填充符号表
1.1 解析 - parseFiles
解析过程将源代码转化为抽象语法树,包含下面两个阶段:1)Scanner进行词法分析:源代码解析为标记token集合;例如int i = 1 包含4个token(int、i、=、1)。2)Parser进行语法分析:token序列到抽象语法树AST(abstract syntax tree);AST是用于描述代码语法结构的树形表示方式,每个节点代表一个语法结构,如包/类型/修饰符/运算符/接口/返回值/注释。编译器的后续操作都针对AST,不会再对源码操作。
1.2 填充符号表
符号表是由一组符号地址和符号信息构成的表格,类似K-V键值对形式。目标代码生成阶段,符号表作为对符号名进行地址分配的依据。
语义检查;产生中间代码;生成默认构造函数;输出待处理列表,包含每个编译单元的AST顶级节点,编译器的编译对象不是java文件,而是待处理列表中各个编译单元的AST顶级节点。
2. 语义分析与字节码生成
1)标注检查:如变量使用前是否声明,变量与赋值的数据类型是否匹配;常量折叠:int a=1+2;会变为int a = 3;
2)数据及控制流分析:flow方法;检查局部变量使用前是否赋值,方法的每条路径是否都有返回值,是否所有checked exception都被正确处理。
3)解语法糖:虚拟机运行时不支持这些语法,他们在编译后还原成基础语法结构。
4)字节码生成:ClassWriter.writeClass(); 把前面生成的AST/符号表转化为字节码写入磁盘,少量的代码添加/转换。如实例/类构造器在这个阶段添加到AST,比如把字符串的加操作替换为StringBuilder/Buffer的append操作。
二、语法糖
1)泛型与类型擦除:参数化类型,操作的数据类型是一个参数。在没有泛型之前,map中只能存储object,需要通过down casting转化为具体类型,这一过程容易出错且需要成本。类型擦除指的是泛型被编译后就不见了。这就是为什么不支持method(List<Integer>)和method(List<String>)这种重载方法的方式。
2)自动装箱/拆箱和遍历循环:Integer.valueOf(), Integer.intValue(); foreach Iterator.hasNext,因此使用遍历循环的类都需要实现Iterable接口。
三、插入式注解处理器
检查程序写的好不好的工具,如checkstyle,findbugs等;通过注解处理器API实现一个编译器插件。
网友评论