深入拆解 Java 虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
87446 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
模块四:黑科技 (3讲)
深入拆解 Java 虚拟机
15
15
1.0x
00:00/00:00
登录|注册

15 | Java语法糖与Java编译器

字符串switch
foreach循环
调用桥接方法的情况
桥接方法的访问标识符
生成桥接方法的目的
方法重写与类型擦除
泛型参数的信息在字节码中的存在
限定了继承类的泛型参数
泛型参数的擦除
Integer.intValue方法
IntegerCache.low参数
IntegerCache.high参数
Integer.valueOf方法
Java 10的var关键字的探索
其他语法糖的编译处理
桥接方法的生成
泛型信息的擦除
自动装箱、自动拆箱
其他语法糖
桥接方法
泛型与类型擦除
自动装箱与自动拆箱
总结与实践
Java编译器的协调工作

该思维导图由 AI 生成,仅供参考

在前面的篇章中,我们多次提到了 Java 语法和 Java 字节码的差异之处。这些差异之处都是通过 Java 编译器来协调的。今天我们便来列举一下 Java 编译器的协调工作。

自动装箱与自动拆箱

首先要提到的便是 Java 的自动装箱(auto-boxing)和自动拆箱(auto-unboxing)。
我们知道,Java 语言拥有 8 个基本类型,每个基本类型都有对应的包装(wrapper)类型。
之所以需要包装类型,是因为许多 Java 核心类库的 API 都是面向对象的。举个例子,Java 核心类库中的容器类,就只支持引用类型。
当需要一个能够存储数值的容器类时,我们往往定义一个存储包装类对象的容器。
对于基本类型的数值来说,我们需要先将其转换为对应的包装类,再存入容器之中。在 Java 程序中,这个转换可以是显式,也可以是隐式的,后者正是 Java 中的自动装箱。
public int foo() {
ArrayList<Integer> list = new ArrayList<>();
list.add(0);
int result = list.get(0);
return result;
}
以上图中的 Java 代码为例。我构造了一个 Integer 类型的 ArrayList,并且向其中添加一个 int 值 0。然后,我会获取该 ArrayList 的第 0 个元素,并作为 int 值返回给调用者。这段代码对应的 Java 字节码如下所示:
public int foo();
Code:
0: new java/util/ArrayList
3: dup
4: invokespecial java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: iconst_0
10: invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
13: invokevirtual java/util/ArrayList.add:(Ljava/lang/Object;)Z
16: pop
17: aload_1
18: iconst_0
19: invokevirtual java/util/ArrayList.get:(I)Ljava/lang/Object;
22: checkcast java/lang/Integer
25: invokevirtual java/lang/Integer.intValue:()I
28: istore_2
29: iload_2
30: ireturn
当向泛型参数为 Integer 的 ArrayList 添加 int 值时,便需要用到自动装箱了。在上面字节码偏移量为 10 的指令中,我们调用了 Integer.valueOf 方法,将 int 类型的值转换为 Integer 类型,再存储至容器类中。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入讨论了Java编译器的协调工作和语法特性,重点探讨了自动装箱和自动拆箱、泛型与类型擦除以及桥接方法。自动装箱和自动拆箱是Java编译器在处理基本类型和包装类型转换时的协调工作,而泛型的类型擦除则是为了兼容引入泛型之前的代码。此外,文章还详细解释了桥接方法在Java字节码层面重写父类方法的作用。另外,还介绍了foreach循环和字符串switch的编译处理。读者可以通过本文更好地理解Java语言的底层实现和特性。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Java 虚拟机》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(20)

  • 最新
  • 精选
  • 本节还是比较容易理解的,也搞清楚了泛型相关的疑惑点,非常感谢。 小结如下: 1:Java语法糖-是一种帮助开发人员提高开发效率的小甜点,原理是将一些繁琐的事情交给编译器来处理,开发人员少做一些事情,当然,本纸上这些事情还必须要做,只是有编译器来做了 2:Java语法糖有那几种呢?如下所示: 2-1:包装类型和基本类型间的转换,自动装箱和拆箱的设计 2-2:泛型的设计 2-3:变长参数的设计 2-4:try-with-resources,关闭资源的设计 2-5:在同一个catch代码块中捕获多种异常 2-6:finally代码块总是被执行的设计 2-7:foreach循环数组的设计 2-8:foreach循环Iterable对象的设计 3:编译器的具体实现细节不是很清楚,猜测是识别出对应的语法然后填充上对应的代码,将语法糖还原成其本质-一些重复繁琐的代码块 4:之前有同事问我泛型是怎么实现的? 我讲不出来,只晓得使用泛型后,不需要写类型强转的代码了,如果类型不对也会有提示且编译失败,现在知道的多一点了,本质上类型强转的工作还是必须要做的,只是不是有开发人员来做了,由编译器来做,并且编译器会擦除掉对应的泛型信息,使用合适的父类型来代替,可能是Object类也可能是声明泛型时指定的继承的类

    作者回复: 赞

    2018-08-25
    60
  • ^_^
    C++ 是真泛型,java 较之算是伪泛型

    作者回复: 确实

    2018-11-13
    3
    9
  • Shine
    每次看到示例代码的java字节码就犯懵,觉得很复杂,是不是有必要去了解下字节码

    作者回复: 字节码其实不难的。我会专门写一篇来介绍一下。

    2018-08-25
    6
  • 任鹏斌
    有点落后刚升级到jdk8对10还一无所知

    作者回复: Java新版本的语法糖并不多,我印象中10也只有var

    2018-08-24
    2
  • 李二木
    从实现上说可以设计一个int类型的list,而jdk中arrayList是object类型,这样做是不是为了通用型考虑呢?

    作者回复: 对的

    2018-08-24
    2
    2
  • 403
    相比来看,c#的泛型是真泛型

    作者回复: ;)

    2018-08-26
  • herome
    求老师画图啊

    作者回复: 这一篇貌似没啥地方能够画图的吧?请问你具体对哪一块有疑问?

    2018-08-25
  • 奇怪的是,Java 并不支持对 IntegerCache.low 的更改,也就是说,对于小于 -128 的整数,我们无法直接使用由 Java 核心类库所缓存的 Integer 对象。 这个奇怪的现象到底是为啥呢?

    作者回复: JDK认为用户不需要缓存小于-128的整数。这当然有可能是错误的。

    2018-08-25
  • 永烁星光
    直到这节课逐渐感知到了学习jvm的妙处,我想将这专栏反复看和实践终能消化为自己的知识
    2018-08-25
    18
  • 曲东方
    var保存了泛型信息 var定义变量必须直接初始化,基于初始化的值做类型推导,javac编译期间的语法糖 所以不能声明函数的参数为var类型 foreach语法糖,对于实现了迭代器Iterable<T>接口的类型,使用迭代器方法; foreach对于数组和变长参数的处理方式与上述略有不同,先求数组长度,再做类似while循环遍历
    2018-08-26
    1
    5
收起评论
显示
设置
留言
20
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部