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

本文参考周志明老师的《深入理解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.还有其他的语法糖这里不做介绍

<think>好的,我现在需要回答用户关于编译期作用及其具体任务的问题。用户已经提供了一些引用资料,我需要结合这些资料来组织答案。 首先,我需要明确编译期的定义。根据引用[1]和[2],编译期可以分为不同的阶段,比如前端编译、后端编译和静态提前编译。用户的问题主要关注编译期的作用和任务,所以应该重点放在前端编译阶段,也就是将.java文件转换为.class文件的过程。 接下来,引用[2]提到早期编译期的三个主要部分:解析与填充符号表、注解处理、语义分析与字节码生成。我需要详细解释每个部分的任务。例如,解析阶段包括词法和语法分析,填充符号表是为了后续步骤使用。注解处理部分可能涉及插入式注解处理器,这在引用[3]中也有提到,关于调试时需要注意clean project以确保注解处理器重新运行。 然后,需要说明编译期优化的重点,比如前端编译对程序编码的影响,而后端编译(即时编译)更多影响运行性能。引用[2]指出,JDK1.3之后优化集中在后端,但前端优化依然重要,例如解语法糖(如泛型、自动装箱)和生成字节码。 另外,需要注意用户提供的引用中提到编译期优化对编码的帮助,比如语法糖的处理让代码更简洁。同时,引用[3]提到的编译期注解处理,需要说明其在编译时生成代码或进行验证的作用,这也是编译期的任务之一。 最后,要确保结构清晰,分点列出编译期的作用和任务,并引用对应的资料。同时,生成的相关问题需要与编译期相关,比如前端编译的具体步骤、与运行期优化的区别、语法糖的处理等。</think>编译期是软件开发过程中将源代码转换为可执行代码的关键阶段,主要作用包括语法检查、代码优化和生成中间代码。根据Java语言特性,编译期可分为前端编译(.java→.class)和早期优化两个维度,具体执行以下核心任务: ### 一、编译期的主要作用 1. **代码正确性验证**:通过语法/语义分析检查代码合规性,如变量类型匹配、语法结构正确性[^2] 2. **代码结构优化**:进行常量折叠、语法糖解糖等优化,提升代码执行效率 3. **中间代码生成**:生成与平台无关的字节码(.class文件),为后续JIT编译提供基础[^2] 4. **元数据处理**:解析注解信息并执行注解处理器逻辑,实现编译时代码生成/验证[^3] ### 二、编译期的核心任务流程 1. **解析与符号表构建** - 词法分析:将字符流转换为token序列(如识别关键词`class`) - 语法分析:构建抽象语法树(AST),例如验证`if(condition){...}`结构正确性 - 符号表填充:记录类/方法/字段的元数据信息,如变量作用域信息[^2] 2. **注解处理阶段** ```java // 示例:编译期生成代码的注解处理器 @SupportedAnnotationTypes("com.example.GenerateCode") public class CodeGenerator extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { // 生成新Java源文件 JavaFileObject file = processingEnv.getFiler().createSourceFile("GeneratedClass"); } } ``` 通过多轮次处理注解(需clean操作保证更新生效),实现动态代码生成 3. **语义分析与优化** - 数据流检查:验证变量初始化状态(如局部变量未初始化警告) - 解语法糖:将泛型、自动装箱等语法转换为标准Java语法 ```java // 编译前 List<String> list = new ArrayList<>(); // 解糖后 List list = new ArrayList(); ``` 4. **字节码生成** 生成包含以下结构的.class文件: ``` CONSTANT_Class_info CONSTANT_Methodref_info Code_attribute: stack=2, locals=4, args_size=1 0: new #2 // class java/util/ArrayList ``` ### 三、编译期优化特点 1. **平台无关性**:生成的字节码可在任何JVM运行 2. **静态检查优势**:相比运行期错误,编译错误更易定位 3. **性能平衡**:前端编译优化减少JIT压力(如字符串拼接优化为StringBuilder)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值