从接触Java语言到现在算来也*年了。从一开始在学校用Swing写扫雷、俄罗斯方块到后来正式参加工作开发JavaWeb,要说不去关心Java的编译原理那是不可能的,毕竟大家都是从C语言学起的,自然会好奇Java为什么会比C“强大”(特指方便)那么多。但又有多少人在两三年开发经验的时候会可以去深入了解Java的编译原理?因为了解了这些似乎看上去对工作没有任何帮助,还不如多看一些第三方框架的配置使用方法。但由于我这种锱铢必究的执拗性格,我打算趁着闲暇之际写一写自己对Javac的了解,一来算作自己的一个总结,二来可以抛砖引玉,让牛人指出自己理解上的不足之处,以此提高自己。
言归正传。Java之所以能实现跨平台,主要得益于JVM(Java Virtual Machine)的强大。JVM为什么能实现让Java代码可以跨平台呢?那就要从Java程序的整个编译、运行的过程说起。
我们写的Java程序是遵循着Java的语言规范,是面向开发者能读懂的语言。但机器不是人,它不能懂“System.out.println("hello world");”是什么意思。你想让cpu为你做事,那你就必须说cpu能听得懂的话,而cpu能听得懂的话就是一个一个的指令。所以你写的Java代码会被先编译成.class文件也就是JVM能读懂的语言,再由ClassLoader将.class文件加载到JVM运行时数据区,并最终由JVM翻译、调用C/C++执行。
我们就先从.Java到.class的编译过程说起。
首先要读取源代码,一个字节一个字节地读进来,找到关键词如if、for、while等,这就是词法分析的过程。这个过程结束以后Java代码就变成了规范的Token流,就像我们把一句话中的名词、动词、标点符号分辨出来。
接着就是对Token流进行语法分析了,比如If后面跟着的是不是一个布尔型的变量,并将符合规范的语法使用语法树存贮起来。之所以要用语法树来存储,是因为这样做可以方便以后对这棵树按照新的规则重新组织,这也是编译器的关键所在。
接下来就是语义分析,编译器可以保证形成语法树以后不存在语法错误,但语义是否正确则无法保证。还有就是Java会有一些相对复杂的语法,语义分析器的作用就是将这些复杂的语法翻译成更简单的语法,比如将foreach翻译成简单的for循环,使它更接近目标语言的语法规则。
最后就是由代码生成器将将语义分析的结果生成符合Java虚拟机规范的字节码了。
所以Java代码变成.class文件所经过的主要步骤有:
1.词法分析器 --->Token流
2.语法分析器 --->语法树
3.语义分析器 --->更加符合目标代码的语法树
4.代码生成器 --->生成.class