深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
27445 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

15 | Java语法糖与Java编译器

郑雨迪 2018-08-24

在前面的篇章中,我们多次提到了 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 类型,再存储至容器类中。

© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(15)

  • godtrue
    本节还是比较容易理解的,也搞清楚了泛型相关的疑惑点,非常感谢。
    小结如下:
    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
    19
  • 永烁星光
    直到这节课逐渐感知到了学习jvm的妙处,我想将这专栏反复看和实践终能消化为自己的知识
    2018-08-25
    8
  • ^_^
    C++ 是真泛型,java 较之算是伪泛型

    作者回复: 确实

    2018-11-13
    2
  • WL
    invokestatic Double.valueOf:(D)Ljava/lang/Double;
    想请教一下老师这个字节码中的(D)和java前的L的作用是标记什么, 查了半天都没查到, 希望老师回答一下.
    2018-12-14
    1
    1
  • 东方
    var保存了泛型信息

    var定义变量必须直接初始化,基于初始化的值做类型推导,javac编译期间的语法糖

    所以不能声明函数的参数为var类型


    foreach语法糖,对于实现了迭代器Iterable<T>接口的类型,使用迭代器方法;
    foreach对于数组和变长参数的处理方式与上述略有不同,先求数组长度,再做类似while循环遍历
    2018-08-26
    1
  • 随心而至
    看老师的课,最好就在电脑边,边看边实践。
    2019-10-16
  • 随心而至
    赞,这节课的内容即便全忘了,也完全可以自己跑自己命令,看下字节码文件,知道到底是怎么回事。这就是授人以渔,谢谢老师。
    2019-10-16
  • 拯救地球好累
    大部分语法糖其实都是编译器为我们提供了一些便利,这些代码在编译后会变成一些基础代码
    自动拆装箱:编译器会插入诸如Integer.valueof方法
    泛型:编译器会根据继承关系做类型擦除
    2019-09-13
  • Zhgdbut
    老师你好,我遇到了一个这种问题
    Long a = null;
    Long rs = 1=1 ? a: 0L;
    报了空指针异常的错误,1=1只是一个条件,表明rs一定等于a!
    请问是咋回事呀?我该怎么修改?
    2019-05-22
    2
  • 403
    相比来看,c#的泛型是真泛型

    作者回复: ;)

    2018-08-26
  • code-artist
    每次看到示例代码的java字节码就犯懵,觉得很复杂,是不是有必要去了解下字节码

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

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

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

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

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

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

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

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

    作者回复: 对的

    2018-08-24
收起评论
15
返回
顶部