关于Java编译

447 阅读5分钟

最近突然很想搞懂一个问题,也是突然想到的,我们知道Java源代码需要编译成.class文件,然后利用JVM解释.class文件,然后再运行。关于JVM,看过《深入理解Java虚拟机》,其中的内容我大致了解了一些,但是不太清楚Java是如何将Java源代码编译成.class文件的(也许是我不太懂编译原理,毕竟本科不是学这个的),于是打算写一篇关于Java编译的博客来梳理一下,当然博客中的绝大部分内容都是我从别的地方看到的,链接我已经放在文章的尾部了。

前言

众所周知,Java是一个编译 + 解释的语言。
编译:将Java源代码编译成字节码文件(.class文件)
解释:通过JVM对字节码文件进行解析,将字节码文件转换成具体平台上的机器指令

这也就是Java能够一次编译,到处运行的原因(平台无关性)。无论你是什么平台,只要安装了JVM,就可以解析 .class 文件,然后转化成机器码。

完整的流程如下图,就不多解释了。

9b751ac1be61ee3058f448c6f2bdfb1.png

Java编译

“编译”的概念

编译的过程就是”编“和”译“。

编:将java源代码的结构组织成合适的格式,包括编译过程中的抽象语法树和符号表等,并在最终将源码编码成为class文件。

译:对源代码中的语义进行解析,并准确地翻译成另一种形式(字节码)。这一步既要确保原格式正确(Java源代码中的语法正确),又要确保翻译后的字节码跟源代码表达的意思一致。

编译器

说到编译,编译器必不可少了。

-   javac:用于编译java源代码,生成class文件;
-   javap:用于反编译,根据class文件,反解析出其中的汇编指令和其他信息;
-   javadoc:用于生成java文档的命令。

如上是Java中常用的命令,其中最重要的是javac命令,这是JDK中内嵌的编译器,通过这个命令,可以将java源文件转换成class文件。这个javac编译器就是JRE相比于JDK少了开发功能的决定性元素!!

当然市面上不止javac这一种编译器,有一些其他的厂商也根据java的标准开发了自己的编译器。例如Eclipse的ecj(the Eclipse Compiler for Java)等。

编译过程

编译器把一种语言规范转化为另一种语言规范的这个过程需要哪些步骤?回答这个问题需要参照《编译原理》,总结过程如下:

1、词法分析:读取源代码,一个字节一个字节的读进来,找出这些词法中我们定义的语言关键词如:if、else、while等,识别哪些if是合法的哪些是不合法的。这个步骤就是词法分析过程。

词法分析的结果:就是从源代码中找出了一些规范化的token流,就像人类语言中,给你一句话你要分辨出哪些是一个词语,哪些是标点符号,哪些是动词,哪些是名词。

2、语法分析:就是对词法分析中得到的token流进行语法分析,这一步就是检查这些关键词组合在一起是不是符合Java语言规范。如if的后面是不是紧跟着一个布尔型判断表达式。

语法分析的结果:就是形成一个符合Java语言规定的抽象语法树,抽象语法树是一个结构化的语法表达形式,它的作用是把语言的主要词法用一个结构化的形式组织在一起。这棵语法树可以被后面按照新的规则再重新组织。

3、语义分析:语法分析完成之后也就不存在语法问题了,语义分析的主要工作就是把一些难懂的,复杂的语法转化成更简单的语法。就如难懂的文言文转化为大家都懂的百话文,或者是注释一下一些不懂的成语。

语义分析结果:就是将复杂的语法转化为简单的语法,对应到Java就是将foreach转化为for循环,还有一些注释等。最后生成一棵抽象的语法树,这棵语法树也就更接近目标语言的语法规则。

4、字节码生成:将会根据经过注释的抽象语法树生成字节码,也就是将一个数据结构转化为另外一个数据结构。就像将所有的中文词语翻译成英文单词后按照英文语法组装文英文语句。代码生成器的结果就是生成符合java虚拟机规范的字节码。

这个过程所需要的组件如下图所示

image.png

总的流程如下

b5f9b11470b30793d39d45ca4aea91c.png

总结

词法分析就是将关键词组织成token流,即检查源码中的的关键词是否真确并组织成token流;
语法分析就是检查源码是否符合java语法规范并将词组成语句。
语义分析就是简化复杂的添加缺少的,检查变量类型是否合法。
代码生成器就是遍历这棵树生成符合JVM规范的代码。

参考文章:
blog.csdn.net/weixin_4616…
blog.csdn.net/fuzhongmin0…