Javac编译过程
Posted lxydo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javac编译过程相关的知识,希望对你有一定的参考价值。
引入
Java的编译器先将其编译为class文件,也就是字节码,这一步称为Javac编译;然后将字节码交由jvm(java虚拟机)解释执行,因而很多地方说“java是一种半编译、半解释执行”的语言。当然现在由于JIT的出现,这种说法有部分是错误的。接下来的两篇博客,会简略介绍一下Javac 编译过程和JIT机制。
Javac编译过程
Javac编译器将.java文件编译成为.class文件的过程,这里的Javac编译器称为前端编译器;相对应的还有后端编译器,它在程序运行期间将字节码转变成机器码。
Javac编译(前端编译)包括 词法、语法分析 、填充符号表 、语义分析、字节码生成。
词法、语法分析
词法分析是将源代码的字符流转变为标记(Token)集合。单个字符是程序编写过程中的的最小元素,而标记则是编译过程的最小元素,关键字、变量名、字面量、运算符等都可以成为标记。例如,下面这行代码
int num = a + 6;
这行代码包含了6个标记,分别是 int 、 num 、 = 、 a 、+ 、 6;
这里的整型标志int虽然由三个字符构成,但是它只是一个标记,不可拆分。
词法分析的作用是将Java源文件的字符流转变成对应的Token系列。而语法分析是将词法分析生成的Token序列来构建更加结构化的抽象语法树的过程。
抽象语法树是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点都代表着程序代码中的一个语法结构,例如包、类型、修饰符、运算符、接口、返回值甚至代码注释等都可以是一个语法结构。语法分析过程由com.sun.tools.javac.parser.Parser类实现,这个阶段产出的抽象语法树由com.sun.tools.javc.tree.JCTree类表示。
经过这个步骤之后,编译器就基本不会再对源码文件进行操作了,后续的操作都是建立在抽象语法树上。
填充符号表
符号表是由一组符号地址和符号信息构成的表格。在目标代码生成阶段,对符号名进行地址分配时,符号表是地址分配的依据。
可以把它想象成哈希表K-V值对,或者javascript中键值对的形式。
一个类除了类本身会定义一些符号变量如类名称、变量名称和方法名称等,还有一些符号是引用其它类的,这些符号会调用其它类的方法或者变量等,还有一些类可能会继承或者实现超类和接口等。这些符号都是在其他类中定义的,那么就需要将这些类的符号也解析到符号表中。
记载的信息通常是标识符(identifier)的相关信息,如类型,作用域等。它通常会在语义分析(Semantic Analysis)阶段运用到,如我们在语法分析(Syntax Analysis)阶段是不会处理这样的情况的:
int a;
a = "Hello,World!";
而这种情况,我们则可以在语义分析分析阶段,利用Symbol Table进行处理,识别出类型的不匹配情况。
语义分析
语法树能表示一个结构正确的源程序的抽象,但无法保证源程序是符合逻辑的。而语义分析的主要任务是读结构上正确的源程序进行上下文有关性质的审查。
语义分析过程分为标注检查和数据及控制流分析两个步骤:
- 标注检查步骤检查的内容包括诸如变量使用前是否已被声明、变量和赋值之间的数据类型是否匹配等。
- 数据及控制流分析是对程序上下文逻辑更进一步的验证,它可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理了等问题。
字节码生成
字节码生成阶段不仅仅是把前面各个步骤所生成的信息转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。 实例构造器()方法和类构造器()方法就是在这个阶段添加到语法树之中的。
字节码生成结束后,.java文件就变成.class文件了,在执行Java程序时 ,字节码由JVM逐条解释执行。不过这是在JIT出现之前的情况了,下篇将介绍JIT。
笔者也是边学边写,如有错误,请在评论中指正。
以上是关于Javac编译过程的主要内容,如果未能解决你的问题,请参考以下文章