JAVA虚拟机精讲-第二章 字节码的编译原理(二)

0x00 字节码

Java跨平台的基石,实现“Write Once, Run Anywhere”

0x01 javac编译器

javac主要工作是把java、源码编译成字节码,除了jdk的javac,还有Eclipse Compiler for java (ECJ)。javac是全量式的编译,而ECJ增量式的编译器,只编译未编译的部分,所以一般ECJ比较快。前端编译器一般不直接涉及编译优化等技术,一般交个JVM,例如hotspot的JIT编译器负责。EJC也是tomcat的默认jsp的编译器。

javac -h 获取帮助.简单编译

javac **.java

 0x02 编译过程:

词法分析-语法分析-(注解插入处理)-语义分析-字节码

javac编译器编译过程分为三个步骤,解析填充符号表,插入式注解处理器的注解处理过程,分析与字节码生产过程。

参考(http://blog.csdn.net/shaozengwei/article/details/38659569)

**Javac编译器的入口是com.sun.tools.javac.main.JavaCompiler类,主要逻辑集中在compile和compile2方法中

  •  解析填充符号表
    词法分析:将源代码的字符流转变为标记(Token)集合。 (Token其实就是一组源码字符集合的单词序列,是一个枚举类型)  com.sun.tools.javac.parser.Scanner类进行词法分析,主要方法:key(Name name)获取指定Token;nextToken()获取;parseCompilationUnit()进行词法解析。

语法分析:用标记序列构造抽象语法树(AST,Abstract Syntax Tree)。Eclipse  AST View插件可以用来查看抽象语法树 。关键类 com.sun.tools.javac.tree.JCTree ,语法树种的每个语法节点实际上直接或间接地继承了JCTree. com.sun.tools.javac.tree.TreeMaker负责创建所有语法节点的对象实例。主要方法:qualident(),调用Ident(Name)解析出JCIdent语法节点或调用Select()解析出JCFieldAccess语法节点。

  • 注解处理器
    Java1.5之后提供了对注解(Annotations)的支持,注解处理器可以理解为抽象语法树的一组插件,这些插件可以对抽象语法树直接进行读取,修改,添加操作。
    如果在解析注解期间,对语法树进行了修改,那么编译器回到解析及填充符号表的过程重新处理,直到所有的插入式注解处理器没有对语法树进行修改为止。
    JavacCompiler 类中initProcessAnnotations()方法对注解处理器进行初始化,JavacProcessingEnvironment类的doProcessing()方法生成新的JavacCompiler对编译的后续过程进行处理。
  • 语义分析与字节码生成
    语法分析之后编译器得到程序的抽象语法树表示,语法树表示一个结构正确的源程序抽象,但无法保证源程序是符合逻辑的,语义分析就是对结构正确的源程序上下文进行审查。
    语法分析与字节码生成总共分为,标注检查,数据及控制流分析,解语法糖,字节码生成四个过程。
    标注检查,和数据及控制流分析主要是对程序上下文环境进行分析检查。
    解语法糖:在Java中常用到的解语法糖就是泛型,在Java虚拟机是不支持泛型的。只是通过语法糖进行语法扩展。

0x03 javap 分析字节码

字节码前四个字节是:0xCAFEBABE,是magic,用于检验是否是有效且合法的字节码文件。反编译命令:

javap -c  xxx

 

使用GCJ 编译器可以把java程序编译成机器码,使之脱离jvm环境。缺点是编译文件很大,而且只对基础类库提供支持。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据