原文地址:https://www.sudo.ren/article/82
Java之所以能够解决程序的安全性、跨平台移植性问题,主要原因就是Java源代码的编译结果并不是本地指令,而是字节码文件。
开发人员在使用Java语言编写一个Java程序的时候需要遵守Java语法规范,而降源代码编译为字节码的时候有需要符合JVM规范,
简单来说,前端编译器的主要任务就是负责将符合Java语法贵方的Java代码转换为符合JVM规范的字节码文件。JVM并不会与Java
语言“终生绑定”,任何语言编写的程序都可以运行在JVM中,前提是源码的编译结果满足并包含Java虚拟机的内部指令集、符号表、
以及其他的辅助信息,他就是一个有效的字节码文件,就能被虚拟机所识别并装载运行。
编译器简介:
Javac.exe:
Java前端编译器全量编译;
负责将符合Java语法规范的Java代码转换为符合JVM规范的字节码文件;
前端编译器并不会直接涉及编译优化等技术,而是将具体细节移交给HotSpot的JIT编译器负责。ECJ:
Eclipse缺省前端编译器,增量编译,比javac更高效;
编译的字节码文件与javac一样。编译原理:
词法解析:将java源码中的关键字和标识符转换为符合java语法规范的Token序列,
然后按照指定的排序规则进行匹配校验。语法解析:将词法解析后的Token序列整合为一颗结构化的抽象语法树。
语义解析:将抽象语法树补充得更加完善。
生成字节码。
词法解析:主要将Java源码中的关键字和标示符等内容转换为符合Java语法规范的Token序列,然后按照指定的顺序规则进行匹配校验,
以便为后续的语法解析步骤做准备。
Scanner类:按照单个字符的方式读取Java源文件中的关键字和标示符;
com.sun.tools.javac.parser.JavacParser类:将Scanner类读取的字符转换为符合Java语法规范的Token序列,
该类的对象实例由ParserFactory工厂负责创建;JavacParser类的parseCompilationUnit()方法:由该方法负责调用Scanner类的nextToken()方法,
获取出Token后再按照指定的顺序规则进行匹配校验;Token序列:一组对应源码字符集合的单词序列(一个枚举类型)。
词法解析器又是采用什么方式保存源码字符集合与Token之间的对应关系?
答:先将每一个字符集合都转换为一个对应的Name对象,然后再由com.sun.tools.javac.parser.Keywords类负责实际的Token转换任务。
Keywords类会将Token中的所有枚举常量全部都转换为Name对象,然后将其存储在Name对象的内部类Table中,
这样一来源码字符集合与Token之间的对应关系就成功构建起来了。
源码字符集合是如何转换成Token的?
答:当词法解析器需要将源码字符集合转换为Token时,就会通过Names类去调用Name类的fromChars()方法获取一个Name对象,
然后在调用Keywords类的key()方法时传入这个Name对象就可以成功获取出对应的Token,
这样一来词法解析器即可成功地将源码将字符集合转换为Token。
语法解析:词法解析的Token序列并不完善,只是一个对应的单个源码字符集合,此时语法解析的任务就是将这些零散的Token
按照指定的Java语法规范整合起来形成一个有机的整体。
JCTree类:语法树中的每一个语法节点都会直接或间接地继承了JCTree,
与语法树中的每一个节点都保持着密不可分的关系。
parseCompilationUnit方法:
1.包含词法解析方法
2.包含语法解析方法
调用qualident() 解析package节点
调用importDeclaration() 解析import节点
调用classDeclarartion() 解析class节点
语意解析:
为没有构造方法的类型添加缺省的无参构造方法;
检查任何类型的变量在使用前是否都已经经历过初始化;
检查变量类型是否与值匹配;
将String类型的常量进行合并处理;
检查代码中的所有操作语句是否可达;
异常检查;
解除Java语法糖。
生成字节码:com.sun.tools.javac.jvm.Gen类
JVM的架构模型是基于栈的操作,所有操作都是出栈和入栈。
前4个字节:0xCAFEBABE --> magic
5,6字节:次编译版本号
7,8字节:主编译版本号
一组8字节(64位)单位的字节流组成了一个完整的字节码文件。
GCJ编译器:将java源码直接编译为本地机器指令。
JavaInJava:寄生在宿主机运行字节码文件。
需要前端编译器编译字节码文件;
宿主机装载字节码文件到其内部;
没有JIT编译器,只靠解释器,所以效率低下。Maxine:
内置JIT编译器;
编译结果为本地指令;
不依赖宿主机独立运行。