前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM第五卷---编译期处理

JVM第五卷---编译期处理

作者头像
大忽悠爱学习
发布2022-05-10 15:22:26
8800
发布2022-05-10 15:22:26
举报
文章被收录于专栏:c++与qt学习

JVM第五卷---编译期处理


编译期处理

所谓的 语法糖 ,其实就是指 java 编译器把 *.java 源码编译为 *.class 字节码的过程中,自动生成 和转换的一些代码,主要是为了减轻程序员的负担,算是 java 编译器给我们的一个额外福利(给糖吃 嘛)

注意,以下代码的分析,借助了 javap 工具,idea 的反编译功能,idea 插件 jclasslib 等工具。

另外,编译器转换的结果直接就是 class 字节码,只是为了便于阅读,给出了 几乎等价 的 java 源码方式,并不是编译器还会转换出中间的 java 源码,切记。

默认构造器

代码语言:javascript
复制
public class Candy1 { }

编译成class后的代码

在这里插入图片描述
在这里插入图片描述

自动拆装箱

这个特性是 JDK 5 开始加入的, 代码片段1 :

在这里插入图片描述
在这里插入图片描述

这段代码在 JDK 5 之前是无法编译通过的,必须改写为 代码片段2 :

在这里插入图片描述
在这里插入图片描述

显然之前版本的代码太麻烦了,需要在基本类型和包装类型之间来回转换(尤其是集合类中操作的都是包装类型),因此这些转换的事情在 JDK 5 以后都由编译器在编译阶段完成。即 代码片段1 都会在编译阶段被转换为 代码片段2


泛型集合取值–泛型擦除

泛型也是在 JDK 5 开始加入的特性,但 java 在编译泛型代码后会执行 泛型擦除 的动作,即泛型信息在编译为字节码之后就丢失了,实际的类型都当做了 Object 类型来处理:

在这里插入图片描述
在这里插入图片描述

所以在取值时,编译器真正生成的字节码中,还要额外做一个类型转换的操作:

在这里插入图片描述
在这里插入图片描述

如果前面的 x 变量类型修改为 int 基本类型那么最终生成的字节码是:

在这里插入图片描述
在这里插入图片描述

还好这些麻烦事都不用自己做。

擦除的是字节码上的泛型信息,可以看到 LocalVariableTypeTable 仍然保留了方法参数泛型的信息

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

局部变量没有办法通过反射的方式,拿到泛型信息,只有在方法的参数和返回值上带的泛型信息才可以通过反射获取到

使用反射,仍然能够获得这些信息:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

输出

在这里插入图片描述
在这里插入图片描述

可变参数

可变参数也是 JDK 5 开始加入的新特性:

例如:

在这里插入图片描述
在这里插入图片描述

可变参数 String… args 其实是一个 String[] args ,从代码中的赋值语句中就可以看出来。同样 java 编译器会在编译期间将上述代码变换为:

在这里插入图片描述
在这里插入图片描述

注意

如果调用了 foo() 则等价代码为 foo(new String[]{})创建了一个空的数组,而不会传递null 进去


foreach 循环

仍是 JDK 5 开始引入的语法糖,数组的循环:

在这里插入图片描述
在这里插入图片描述

会被编译器转换为:

在这里插入图片描述
在这里插入图片描述

而集合的循环:

在这里插入图片描述
在这里插入图片描述

实际被编译器转换为对迭代器的调用:

在这里插入图片描述
在这里插入图片描述

注意

foreach 循环写法,能够配合数组,以及所有实现了 Iterable 接口的集合类一起使用,其中Iterable 用来获取集合的迭代器( Iterator )


switch 字符串

从 JDK 7 开始,switch 可以作用于字符串和枚举类,这个功能其实也是语法糖,例如:

在这里插入图片描述
在这里插入图片描述

注意

switch 配合 String 和枚举使用时,变量不能为null,原因分析完语法糖转换后的代码应当自然清楚

会被编译器转换为:

在这里插入图片描述
在这里插入图片描述

可以看到,执行了两遍 switch,第一遍是根据字符串的 hashCode 和 equals 将字符串的转换为相应byte 类型,第二遍才是利用 byte 执行进行比较。

为什么第一遍时必须既比较 hashCode,又利用 equals 比较呢

hashCode 是为了提高效率,减少可能的比较;而 equals 是为了防止 hashCode 冲突例如 BM 和 C. 这两个字符串的hashCode值都是2123 ,如果有如下代码:

在这里插入图片描述
在这里插入图片描述

会被编译器转换为:

在这里插入图片描述
在这里插入图片描述

switch 枚举

switch 枚举的例子,原始代码:

在这里插入图片描述
在这里插入图片描述

转换后代码:

在这里插入图片描述
在这里插入图片描述

枚举类

JDK 7 新增了枚举类,以前面的性别枚举为例:

代码语言:javascript
复制
enum Sex { MALE, FEMALE }

转换后代码:

在这里插入图片描述
在这里插入图片描述

try-with-resources

JDK 7 开始新增了对需要关闭的资源处理的特殊语法 try-with-resources:`

在这里插入图片描述
在这里插入图片描述

其中资源对象需要实现 AutoCloseable 接口,例如 InputStream 、 OutputStream 、 Connection 、 Statement 、 ResultSet 等接口都实现了 AutoCloseable ,使用 try-with- resources 可以不用写 finally 语句块,编译器会帮助生成关闭资源代码,例如:

在这里插入图片描述
在这里插入图片描述

会被转换为:

在这里插入图片描述
在这里插入图片描述

为什么要设计一个 addSuppressed(Throwable e) (添加被压制异常)的方法呢?是为了防止异常信息的丢失(想想 try-with-resources 生成的 fianlly 中如果抛出了异常):

在这里插入图片描述
在这里插入图片描述

输出:

在这里插入图片描述
在这里插入图片描述

如以上代码所示,两个异常信息都不会丢


方法重写时的桥接方法

我们都知道,方法重写时对返回值分两种情况:

  • 父子类的返回值完全一致
  • 子类返回值可以是父类返回值的子类(比较绕口,见下面的例子)
在这里插入图片描述
在这里插入图片描述

对于子类,java 编译器会做如下处理:

在这里插入图片描述
在这里插入图片描述

其中桥接方法比较特殊,仅对 java 虚拟机可见,并且与原来的 public Integer m() 没有命名冲突,可以用下面反射代码来验证:

代码语言:javascript
复制
for (Method m : B.class.getDeclaredMethods()) 
{ System.out.println(m); }

会输出:

代码语言:javascript
复制
public java.lang.Integer test.candy.B.m() 
public java.lang.Number test.candy.B.m()

匿名内部类

源代码:

在这里插入图片描述
在这里插入图片描述

转换后代码:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

引用局部变量的匿名内部类,源代码:

在这里插入图片描述
在这里插入图片描述

转换后代码:

在这里插入图片描述
在这里插入图片描述

注意

这同时解释了为什么匿名内部类引用局部变量时,局部变量必须是 final 的:因为在创建Candy111 对象时,将 x 的值赋值给了 Candy111 对象的 valx 属性,所以 x 不应该再发生变化了,如果变化,那么 valx 属性没有机会再跟着一起变化


插入式注解处理器

插入式注解处理器可以看做是一组编译器插件,当这些插件工作的时候,可以读取,修改和添加抽象语法树中任意的元素。

如果这些插件在处理注解期间对语法树进行过修改,编译器将会到解析及填充符号表的过程重新处理,直到所有插入式注解处理器都没有再对语法树进行修改为止,每一次循环称为一个轮次。

著名的Lombok就是通过插入式注解处理器实现的。

打包自定义插入式注解: https://www.cnblogs.com/avenwu/p/4173899.html 获取类、字段:https://blog.csdn.net/zhuhai__yizhi/article/details/51394810 编辑语法树:https://blog.csdn.net/a_zhenzhen/article/details/86065063 https://www.cnblogs.com/kanyun/p/11541826.html 生成 GET / SET 方法:https://www.jianshu.com/p/68fcbc154c2f

插入式注解-自动生成 Get / Set

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM第五卷---编译期处理
  • 编译期处理
    • 默认构造器
      • 自动拆装箱
        • 泛型集合取值–泛型擦除
          • 可变参数
            • foreach 循环
              • switch 字符串
                • switch 枚举
                  • 枚举类
                    • try-with-resources
                      • 方法重写时的桥接方法
                        • 匿名内部类
                        • 插入式注解处理器
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档