Java前段编译优化

前端编译器:把*.java文件转变成*.class文件的过程(代表:JDK的Javac)
即时编译器(JIT编译器):运行期把字节码转变成本地机器码的过程(代表:HotSpot虚拟机的C1、C2编译器)
提前编译器:直接把程序编译成与目标机器指令集相关的二进制代码的过程(代表:JDK的Jaotc、Excelsior JET)

Java中即时编译器在运行期的优化过程,支撑了程序执行效率的不断提升;而前端编译器在编译期的优化过程,则是支撑着程序员的 编码效率和语言使用者的幸福感的提高。

Javac编译器

Javac的编译过程分为1个准备过程和3个处理过程:

准备过程:初始化插入式注解处理器。

处理过程:
1)解析与填充符号表过程,包括:
·词法、语法分析。将源代码的字符流转变为标记集合,构造出抽象语法树。
·填充符号表。产生符号地址和符号信息
2)插入式注解处理器的注解处理过程:插入式注解处理器的执行阶段。执行此过程可能会产生新的符号,产生新的符号就必须返回到处理过程第一步,在解析与填充符号表中重新处理新符号。
3)分析与字节码生成过程,包括:
·标注检查。对语法的静态信息进行检查。
·数据流及控制流分析。对程序动态运行过程进行检查。
·解语法糖。将简化代码编写的语法糖还原为原有的形式。
·字节码生成。将前面各个步骤所生成的信息转化成字节码。
在这里插入图片描述在这里插入图片描述
解析与填充符号表

词法分析是将源代码的字符流转变为标记(Token)集合的过程,单个字符是程序编写时的最小元 素,但标记才是编译时的最小元素。关键字、变量名、字面量、运算符都可以作为标记.

语法分析是根据标记序列构造抽象语法树的过程,抽象语法树(Abstract Syntax Tree,AST)是一种用来描述程序代码语法结构的树形表示方式,抽象语法树的每一个节点都代表着程序代码中的一个语法结构。经过词法和语法分析生成语法树以后,编译器就不会再对源码字符流进行操作了,后续的操作都 建立在抽象语法树之上。

符号表(Symbol Table)是由一组符号地址和符号信息构成的数据结构.

注解处理器

注解原先只会在运行期间发挥作用,JDK6之后在前段编译期间可以对特定的注解进行处理(插入时注解处理器)。当注解处理器工作时允许读取、修改、添加抽象语法树中的任意元素。如果在此期间有对语法树进行过修改,编译器将回到解析及填充符号表的过程重新处理,知道所有的插入式注解处理器都没有对语法树进行修改为止。常见的插入时注解器:Lombok

语义分析与字节码生成

语义分析:虽然获得了程序的语法树,但是还没有对其进行检查,无法保证源程序的语义是符合逻辑的。 对结构上正确的源程序进行上下文相关性质的检查,譬如进行类型检查、控制流检查、数据流检查等,叫做语义分析。编码时经常能在IDE 中看到由红线标注的错误提示,其中绝大部分都是来源于语义分析阶段的检查结果。Javac在编译过程中,语义分析过程可分为标注检查和数据及控制流分析两步。

1.标注检查:包括诸如变量使用前是否已被声明、变量与赋值之间的数据类型是否 能够匹配、常量折叠等等
2.数据及控制流分析:对程序上下文逻辑更进一步的验证,诸如程序局部变量 在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理了等问题。

解语法糖:语法糖指的是在计算机语言中添加的某种语法,这种语法对语言的编译结果和功能并没有实际影响, 但是却能更方便程序员使用该语言。语法糖能够减少代码量,增加程序可读性,减少代码出错的机会。常见的比如自动装箱拆箱、泛型、变长参数等。

泛型:Java中采取类型擦除式泛型,就是在将程序中的泛型在编译的时候全部打回成裸类型,在运行时再从裸类型转化成原先的数据类型。比如ArrayList< Integer > 和ArrayList< String >,虽然在程序中不同,但是编译器会将Integer和String全部打T,在Code文件中最后记录的都会时ArrayList< T >,等代码执行时再将T转换成Integer和String.此处的类型擦除只是再Code属性中字节码部分,而元数据是没有擦除的,它保留了泛型信息,这也是在编码时能通过反射手段取得参数化类型的根本依据。。

泛型引起的重载问题:ArrayList< String >和ArrayList< Integer >是不同的类型,但是却无法重载,因为最后字节码收到的都是ArrayList< T>。方法的重载是类型、顺序和个数,但是此处类型不同却无法重载。但是如果此处返回值不同,就可以重载。因为代码时的重载特签名不包括返回值,但是再Class文件层面描述符不同两个文件就可以共存,描述符包含返回值。

自动拆装箱:自动装箱、拆箱在编译之后被转化 成了对应的包装和还原方法

遍历循环:遍历循环则是把代码还原成了迭代器的实现,这也是为何遍历循环需要被遍历的类实现Iterable接口的原因

字节码生成:前面各个步骤所生成的信息(语法树、符号表)转化成字节码指令 写到磁盘中

可以看到,在前端编译器阶段,编译器并没有对代码本身做改变,它只是把程序由源文件变成了Class文件,并在过程中做一些检查,将语法糖等简化开发的转变出了个底层的实现。这些措施可以简化程序开发但是并没有对程序运行时的效率进行改变。而Java的即使编译器在运行期间优化,支撑了程序执行效率的不断提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值