JVM::早期(编译期)优化

本文介绍了Java编译过程中的关键步骤,包括解析与填充符号表、注解处理、语义分析以及字节码生成等内容,并详细解释了Java中的几种语法糖机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文参考周志明老师的《深入理解Java虚拟机》

一.Javac编译器

1.解析与填充符号表

a.解析:parseFiles();

词法分析将源代码的字符流转化为标记(Token)集合。

语法分析根据Token序列构造抽象语法树。

b.填充符号表:enterTress();

符号表是K—V键值对的形式。

2.注解处理器

如果注解处理器在处理注解的时候对语法树进行了修改,编译器将回到解析与填充符号表过程重新处理,知道所有插入式注解处理器都没有再对语法树进行修改为止。每一次循环成为一次Round,即下图的回环:

3.语义分析和字节码生成

a.标注检查:attribute()

检查变量使用前是否已经被声明,变量与赋值之间的数据类型是否能够匹配。

b.数据及控制流分析:flow()

检查局部变量在使用前是否有被赋值,方法的每条路径是否都有返回值,是否所有的受查异常都被正确处理了等问题。

c.解语法糖:desugar()

泛型,可变参,自动拆装箱

4.字节码生成generate()

把前面各个步骤所声称的信息的(语法树,符号表)转化到字节码写入磁盘中,还对少量代码添加和转换。<init>()和<clinit>就是这个阶段添加到语法树之中的。

编译器会把语法块、变量初始化、调用父类的实例构造器等操作收敛到<init>()和<cliinit>()之后。且一定保证先执行父类实例构造器,然后初始化变量,最后执行语句块(对<init>()来说就是{...},对<clinit>来说就是static{...})的顺序。

二.语法糖

1.泛型和类型擦除

本质是参数化类型的应用。即:所操作的数据类型被指定为一个参数。这个参数类型可以用在类、接口、方法的创建中。

java的泛型只存在与源码之中,编译后的字节码文件,就已经替换为原来的原生类型(Raw Type,也成为裸类型),并且在相应的地方插入了强制转化代码。Java语言中泛型实现方法被称为类型擦除,是伪泛型。

擦除仅仅是对方法的Code属性中的字节码进行擦除,实际上元数据还是保留了泛型的信息,这也是我们能通过反射取得参数化类型的根本依据。

2.自动装箱拆箱与循环遍历

自动装箱拆箱在编译之后就成了对应的包装和还原方法;循环便利把代码还原成了迭代器的实现,这也是为何遍历循环需要被遍历的类实现Iterable接口。

3.条件编译

只有使用条件为常量的if语句才能达到。

public static void main(String[] args) {
    if(true) {
        System.out.println("this line will be reserved");
    } else {
        System.out.println("this line will not be reserved");
    }
}

将会变成:

public static void main(String[] args) {
    System.out.println("this line will be reserved");
}

4.还有其他的语法糖这里不做介绍

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值