将.java文件编译成.class文件。
为什么要编译为.class(十六进制字节码)文件? JVM虚拟机,只能识别符合虚拟机规范的十六进制字节码文件。
java夸平台特性和编译关系?一次编译多系统执行。
编译好的字节码可以在多个系统下JVM虚拟机中运行。(不同系统安装不同JVM虚拟机)
源码到字节码编译过程流程图
词法分析器:将源码代码的字符流转变为Token流
语法分析器:通过Token流进行语法分析产生语法树或抽象语法树
语义分析器:1.标注检查。2.数据和控制流分析。3.解析语法糖。
标注检查:对语法的静态信息进行检查。
检查内容包括:变量使用是否已被声明,变量与赋值的数据类型是否匹配等等
这个期间还会进行常量重叠优化。
数据流和控制流分析:对程序动态运行过程的进行检查。
检查内容包括:检查局部变量在使用前是否有赋值,方法的每条路基是否有返回值
是否所有异常被正确处理等问题。
解析语法糖:将简化的语法糖还原到基础语法结构。
字节码生成器:实例构造器(<init>())和类构造器方法(<clinit>())就是在这个期间添加到语法树的
符号表: 一组符号地址和符号信息构成的表格。符号表编译不同阶段都有用到
例如:语义分析 检测使用变量名称类型是否和声明类型一致。
何如将.java文件编译成.class文件。
结合源码分析:
入口:com.sun.tools.javac.main.JavaCompiler 类 compile 方法
图中 parseFiles 方法功能
1.将.java内容读取到内存中 readSource(filename))
2.词法分析
将源码代码的字符流转变为标记(Token)集合例如:int a=b+2 收集6个标记 int,a,=,b,+,2)
3.语法分析
词法分析的标记(Token)集合构造成抽象语法树。
抽象语法树,用树形描述程序代码语法结构,语法树每个节点都是一个语法结构(包括 包,
类型,修饰符,运算符,接口,返回值,代码注释等)
图中 enterTrees方法功能
使用 enterTrees填充符号表
符号表示一组符号地址和符号信息构成的表格。
符号表编译不同阶段都有用到,例如语义分析 检测使用变量名称类型是否和声明类型一致。
图中processAnnotations方法功能
注解处理器
initProcessAnnotations(processors);//初始化
processAnnotations()//执行过程。
注解中如果对抽象语法数任意元素修改 编译器将重新执行词法和语法和填充符号。直到没有变化为止。
图中delegateCompiler.compile2();方法功能
语义检查和字节码生成。
1.标注检查。
2.数据和控制流分析。
3.解析语法糖。
4.字节码生成。
图中attribute方法功能
检查的内容包括:变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配等。
标注检查步骤在Javac源码中的实现类是com.sun.tools.javac.comp.Attr类和com.sun.tools.javac.comp.Check类。
图中flow方法功能
数据及控制流分析是对程序上下文逻辑更进一步的验证,它可以检查:程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理了等。
编译时期的数据及控制流分析与类加载时的数据及控制流分析的目的基本上是一致的,但校验范围有所区别,有一些校验项只有在编译期或运行期才能进行。
在Javac的源码中,数据及控制流分析的入口是flow()方法,具体操作由com.sun.tools.javac.comp.Flow类完成。
图中desugar方法功能
语法糖(Syntactic Sugar),也称糖衣语法。指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。
Java中最常用的语法糖:泛型、变长参数、自动装箱/拆箱等,虚拟机运行时不支持这些语法,它们在编译阶段还原回简单的基础语法结构,这个过程称为解语法糖。
图中generate方法功能
字节码生成阶段将语法树,符号表转换为字节码写到磁盘同时还进行了少量代码添加和转换工作。
com.sun.tools.javac.main.JavaCompiler 类 generate方法产生 .class文件
com.sun.tools.javac.jvm.ClassFile
存放
public final static int JAVA_MAGIC = 0xCAFEBABE;
Version Enum
V45_3(45, 3), // base level for all attributes
V49(49, 0), // JDK 1.5: enum, generics, annotations
V50(50, 0), // JDK 1.6: stackmaps
V51(51, 0), // JDK 1.7
V52(52, 0); // JDK 1.8: lambda, type annos, param names
com.sun.tools.javac.jvm.ClassWriter 类 writeClass方法将编译好的.java 写到out文件中
poolbuf.appendInt(JAVA_MAGIC);
poolbuf.appendChar(target.minorVersion);
poolbuf.appendChar(target.majorVersion);
总结:
IDE中有红线标注的错误提示绝大部分都是语义分析结果。