一直以为我们常用的javac是“高效"的c或c++代码写成的。直到openjdk中也找到他的身影时才发现java其实是如此的强大,只是我们一直没有挖掘出它的潜力罢了。
可以在com.sun.tool.javac中找到javac的初始调用入口,而真正执行编译的类是com.sun.tools.javac.main.JavaCompiler。
如图:可以将编译的过程分为两个大的步骤:语法分析及符号表生成,语义分析及字节码生成。
实际上第一步执行了预处理,词法分析,语法分析以及填充符号表4步,它的输入是java源文件,输出则是抽象语法树及符号表,而第二步执行了标注检查,控制流分析,解语法糖,字节码生成4步,它的输入是抽象语法树和符号表,输出则是字节码即class文件。
预处理主要是做注解的配置和准备,它在JavaCompiler中的initProcessAnnotation方法中。
词法分析主要是将java的源文件分解为一个一个的token,分析的主要实现(包括词法分析和语法分析)在JavaCompiler中的parse方法中,而词法分析是由com.sun.tools.javac.parser.Scanner的实现来完成的。
语法分析则是根据词法分析生成的token流以及程序的语法结构生成一颗抽象的语法树。语法分析的实现主要是由com.sun.tools.javac.parser.Parser来实现的。
填充符号表是一组符号地址和符号信息构成的表格,主要用于语义分析阶段,由com.sun.tools.javac.comp.Enter来实现的。
标注检查是语义分析前的预检查步骤,主要是检查变量是否声明,数据类型是否匹配,常量折叠等。由com.sun.tools.javac.comp.Attr和Check实现。
控制流分析也是一个检查的步骤,不过它关注的点不同,主要是检查是不是方法的每条路径都有返回值,是不是所有checked异常都被处理了等等。由com.sun.tools.javac.comp.Flow实现。
解语法糖主要目的是将java中的语法糖还原,比如自动封拆箱,泛型,变长参数,for循环等等。由com.sun.tools.javac.comp.TransTypes和Lower实现。
字节码生成则是将前面所有步骤生成的信息写入class文件中,还包括对class的一些修改和优化。由com.sun.tools.javac.jvm.Gen来实现。
参考:《深入理解java虚拟机》