深入理解Javac编译器
介绍
简单的介绍什么是Javac编译器:
javac 是javac语言编程编译器。javac工具读由java语言编写的类和接口的定义,并将它们编译成字节代码的class文件。javac 可以隐式编译一些没有在命令行中提及的源文件。
javac编译过程
1.解析与填充符号表过程
2.插入式注解处理器的注解处理过程(回环过程)。
3.分析与字节码生成过程
图javac编译过程主体代码
1.解析与填充符号表
1.词法和语法分析
parseFile(sourceFileObjects)方法进行词法和语法分析。
词法分析:将源代码的字符流转变为标记token集合,单个字符是程序编写过程的最小元素,而标记则是编译过程最小元素,关键字,变量名,字面量,运算符都可以成为标记,如”int a=b+2”这句话包含了6个标记,关键字int虽然有三个字母但是,只是一个token不可再区分。
语法分析:将token序列构造成抽象语法树的过程,抽象语法树,是一种用来描述程序代码语法结构的属性表示方式,语法树的每一个结点都代表着程序代码中的一个语法结构,如包,类型,修饰符,运算符,接口,返回值甚至代码注释等都可以是一个语法结构。
2.填充符号表
enterTrees调用使用com.sun.tools.javac.comp.Enter类,此过程每个编译单元的抽象语法树的顶局节点都先被放到待处理列表中并逐个处理列表中的节点。所有的类符号被输入到外围作用域的符号表中确定类的参数(对泛型类型而言)、超类型和接口如果需要添加默认构造器,将类中出现的符号输入到类自身的符号表中。符号表可以使得编译期能够快速识别并获取存储的Token信息,以提高JVM的编译效率。
2.注解处理器-回环处理
JDK1.5之后,java提供了对注解的支持,即那些以@开头的声明语句。我们可以把他看做是一组编译器的插件,如果这些插件在处理注解期间对语法树进行了修改,编译器回到解析及填充符号表的过程重新处理,直到所有插入式注解处理器都没有再对语法树进行修改,每一次循环称为一个Round。
3.语义分析和字节码的生成
1)检查操作变量类型是否匹配,操作数|方法返回值类型匹配com.sun.tools.javac.comp.Check
2)检查变量、方法或类的访问是否合法、变量是否是静态变量、变量在使用前是否已经初始化com.sun.tools.javac.comp.Resolve
3)推导出泛型方法中的参数类型com.sum.tools.javac.comp.Infer
4)将一些常量进行合并处理com.sum.tools.javac.comp.ConstFold 例如:int a=1+2;合并之后就是int a=3;
com.sun.tools.javac.comp.Flow数据流分析
5)检查变量在使用前是否已经正确赋值
6)包装final修饰的变量不会被重新赋值
7)方法的返回值类型都要确定
8)检查所有的操作是否可达
9)检查checked exception异常是否已经捕获或抛出
10)解除Java的语法糖
11)去掉无用的代码,如永假的if代码块
12)变量的自动转换,如将int自动包装成Integer类型或者相反的操作等;