一般,一个java文件会经过编译器编译成字节码文件.class,再又java虚拟机JVM翻译成计算机可执行的文件。java
咱们所知道的java语言有它本身的语法规范,一样的JVM也有它的语法规范,如何让java的语法规则去适应语法解析规则,这就是javac的做用,简而言之,javac的做用就是将java源代码转化成class字节码文件。bash
将源码转化为Token流jvm
读取源代码,从源文件的一个字符开始,按照java语法规范依次找出package,import,类定义,属性,方法定义等,最后构建出一个抽象语法树函数
package compile;
/**
* 词法解析器
*/
public class Cifa{
int a;
int c = a + 1;
}
复制代码
转化为Token流: 源码分析
Javac在进行此法分析时会由JavacParser根据Java语言规范来控制什么顺序,地方会出现什么Token,例如package就只能在文件的最开头出现ui
对于关键字,主要由关键字的语法规则,例如package就是若一个字符串package是连续的,那么他就是关键字this
对于自定义变量名称,自定义名称之间用空格隔开,每一个语法表达式用分号结束spa
int a = 1 + 2;翻译
从package开始code
.....
int 就是经过语法关键字断定的TOKEN:INT
int a之间经过空格隔开
a 就是自定义的变量被断定为TOKEN:IDENTIFIER
a =之间经过空格隔开(这时有的小伙伴就会说了,int a=b+c;这句话也不报错啊,对的,大多数时候,这种不用空格分开确实可以编译,这是由于java指出声明变量的时候必须以字母、下划线或者美圆符开头,当JavacParser读完a去读=的时候就直到这个=不属于变量了)将=断定为TOKEN:EQ
1被断定为TOKEN:INTLITERAL
.....
将;识别为TOKEN:SEMI
.....
最后读取到类结束,也就是}被断定为TOKEN:RBRACE
刚才,词法解析器已经将Java源文件解析成了Token流。
如今,语法解析器就要将Token流组建成更加结构化的语法树。也就是将这些Token流中的单词装成一句话,完整的语句。
将进行词法分析后造成的Token流中的一个个Token组成一句句话,检查这一句句话是否是符合Java语言规范。
Tree tag:每一个语法节点都会以整数的形式表示,下一个节点在上一个节点上加1;
复制代码
pos:也是一个整数,它存储的是这个语法节点在源代码中的起始位置,一个文件的位置是0,而-1表示不存在
复制代码
type:它表明的是这个节点是什么java类型,如int,float,仍是string等
复制代码
package compile;
/**
* 语法
*/
public class Yufa {
int a;
private int c = a + 1;
//getter
public int getC() {
return c;
}
//setter
public void setC(int c) {
this.c = c;
}
}
复制代码
注1:若类中有import关键字则途中还有import的语法节点
注2:全部语法节点的生成都是在TreeMaker类中完成的
将语法树转化为注解语法树,即在这颗语法树上作一些处理
给类添加默认构造函数(由com.sun.tools.javac.comp.Enter类完成)
处理注解(由com.sun.tools.javac.processing.JavacProcessingEnvironment类完成)
检查语义的合法性并进行逻辑判断(由com.sun.tools.javac.comp.Attr完成)
数据流分析(由com.sun.tools.javac.comp.Flow类完成)
对语法树进行语义分析(由com.sun.tools.javac.comp.Flow执行)
最终,生成了注解语法树
变量自动转化
public class Yuyi{
public static void main(String agrs[]){
Integer i = 1;
Long l = i + 2L;
System.out.println(l);
}
}
//通过自动转换后
public class Yuyi{
public Yuyi(){
super();
}
public static void main(String agrs[]){
Integer i = Integer.valueOf(1);
Long l = Long.valueOf(i.intValue() + 2L);
System.out.println(l);
}
}
复制代码
解除语法糖
public class Yuyi{
public static void main(String agrs[]){
int[] array = {1,2,3};
for (int i : array){
System.out.println(i);
}
}
}
//解除语法糖后
public class Yuyi{
public Yuyi(){
super();
}
public static void main(String agrs[]){
int[] arrays = {1,2,3};
for (int[] arr$ = array,len$=arr$.length,i$=0; i$<len$; ++i$){
int i = arr$[i$];
{
System.out.println(i);
}
}
}
}
复制代码
内部类解析
public class Yuyi{
public static void main(String agrs[]){
Inner inner = new Inner();
inner.print();
}
class Inner{
public void print(){
System.out.println("Yuyi$Inner.print");
}
}
}
//转化后的代码以下
public class Yuyi{
public Yuyi(){
super();
}
public static void main(String agrs[]){
Yuyi$Inner inner = new Yuyi$Inner(this);
inner.print();
}
{
}
}
class Yuyi$Inner{
/*synthetic*/ final Yuyi this$0;
Yuyi$Inner(/*synthetic*/final Yuyi this$0){
this.this$0 = this$0;
super();
}
public void print(){
System.out.println("Yuyi$Inner.print");
}
}
复制代码
生成语法树后,接下来Javac会调用com.sun.tools.javac.jvm.Gen类遍历语法树,生成Java字节码
参考书籍:《深刻分析Java Web》