基本类型和其包装类型之间的自动转换,也就是自动装箱、自动拆箱,是通过加入[Wrapper].valueOf(如 Integer.valueOf)以及[Wrapper].[primitive]Value(如 Integer.intValue)方法调用来实现的。

  Java 程序中的泛型信息会被擦除。具体来说,Java 编译器将选取该泛型所能指代的所有类中层次最高的那个,作为替换泛型的具体类。

  由于 Java 语义与 Java 字节码中关于重写的定义并不一致,因此 Java 编译器会生成桥接方法作为适配器。

  此外,我还介绍了 foreach 循环以及字符串 switch 的编译。

  1. 自动装箱、自动拆箱
  2. 泛型擦除
  3. foreach循环的编译
  4. switch的编译

1. 自动装箱、自动拆箱

1 public int foo() {
2 ArrayList<Integer> list = new ArrayList<>();
3 list.add(0); // Integer.valueOf()自动装箱 (基本型--> 包装类型)
4 int result = list.get(0); // Integer.intValue()的自动拆箱
5 return result;
6 }
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
1 public static Integer valueOf(int i) {
2 if (i >= IntegerCache.low && i <= IntegerCache.high)
3 return IntegerCache.cache[i + (-IntegerCache.low)]; // 直接从缓存返回,否则new一个对象
4 return new Integer(i);
5 }

2. 泛型擦除

 1 package java8;
2
3 import java.util.ArrayList;
4
5 /**
6 * 既然泛型会被类型擦除,那么我们还有必要用它吗?我认为是有必要的。Java 编译器可以根据泛型参数判断程序中的语法是否正确。
7 * 举例来说,尽管经过类型擦除后,ArrayList.add 方法所接收的参数是 Object 类型,但是往泛型参数为 Integer 类型的
8 * ArrayList 中添加字符串对象,Java 编译器是会报错的。
9 */
10 public class Foo {
11
12 public int foo() {
13
14 /**
15 * 字节码如下
16 13: invokevirtual java/util/ArrayList.add:(Ljava/lang/Object;)Z
17 ...
18 19: invokevirtual java/util/ArrayList.get:(I)Ljava/lang/Object;
19 22: checkcast java/lang/Integer
20
21 生成的字节码中,往 ArrayList 中添加元素的 add 方法,所接受的参数类型是 Object;
22 而从 ArrayList 中获取元素的 get 方法,其返回类型同样也是 Object。
23 */
24 ArrayList<Integer> list = new ArrayList<>();
25 list.add(0);
26 int result = list.get(0);
27 return result;
28 }
29 }
30
31
32 class GenericTest<T extends Number> {
33
34 /**
35 * 当然,并不是每一个泛型参数被擦除类型后都会变成 Object 类。对于限定了继承类的泛型参数,经过类型擦除后,
36 * 所有的泛型参数都将变成所限定的继承类。
37 * 可以看到,foo 方法的方法描述符所接收参数的类型以及返回类型都为 Number。
38 *
39 *
40 T foo(T);
41 descriptor: (Ljava/lang/Number;)Ljava/lang/Number;
42 flags: (0x0000)
43 Code:
44 stack=1, locals=2, args_size=2
45 0: aload_1
46 1: areturn
47 Signature: (TT;)TT;
48 *
49 */
50 T foo(T t) {
51 return t;
52 }
53 }

3. foreach循环的编译

foreach 循环允许 Java 程序在 for 循环里遍历数组或者 Iterable 对象。对于数组来说,foreach 循环将从 0 开始逐一访问数组中的元素,直至数组的末尾。其等价的代码如下面所示:

 1 public void foo(int[] array) {
2 for (int item : array) {
3 }
4 }
5 // 等同于
6 public void bar(int[] array) {
7 int[] myArray = array;
8 int length = myArray.length;
9 for (int i = 0; i < length; i++) {
10 int item = myArray[i];
11 }
12 }

对于 Iterable 对象来说,foreach 循环将调用其 iterator 方法,并且用它的 hasNext 以及 next 方法来遍历该 Iterable 对象中的元素。其等价的代码如下面所示:

 1 public void foo(ArrayList<Integer> list) {
2 for (Integer item : list) {
3 }
4 }
5 // 等同于
6 public void bar(ArrayList<Integer> list) {
7 Iterator<Integer> iterator = list.iterator();
8 while (iterator.hasNext()) {
9 Integer item = iterator.next();
10 }
11 }

4. switch的编译

 1 package java8;
2
3 /**
4 * 字符串 switch 编译而成的字节码看起来非常复杂,但实际上就是一个哈希桶。由于每个 case 所截获的字符串都是常量值,
5 * 因此,Java 编译器会将原来的字符串 switch 转换为 int 值 switch,比较所输入的字符串的哈希值。
6 *
7 * 由于字符串哈希值很容易发生碰撞,因此,我们还需要用 String.equals 逐个比较相同哈希值的字符串。
8 *
9 * tableswitch用于case比较紧凑的代码,而lookup用于case比较分散的代码。
10 * 如果不考虑空间的话,tableswitch指令比lookup指令有更高的执行效率。
11 */
12 public class SwitchTest {
13
14 /**
15 * 1: lookupswitch { // 2
16 * 1: 28
17 * 2: 39
18 * default: 50
19 * }
20 *
21 */
22 void switchGo(int inPut) {
23 switch (inPut) {
24 case 1:
25 System.out.println("***********");
26 break;
27 case 2:
28 System.out.println("#########");
29 break;
30 default:
31 System.out.println("DEFAULT_&&");
32 break;
33 }
34 }
35
36
37 /**
38 * 1: tableswitch { // 0 to 2
39 * 0: 28
40 * 1: 30
41 * 2: 32
42 * default: 34
43 * }
44 *
45 *
46 */
47 int chooseNear(int i) {
48 switch (i) {
49 case 0: return 0;
50 case 1: return 1;
51 case 2: return 2;
52 default: return -1;
53 }
54 }
55 }

JVM-Java语法糖与Java编译器的更多相关文章

  1. JVM总结-Java语法糖与Java编译器

    自动装箱与自动拆箱 首先要提到的便是 Java 的自动装箱(auto-boxing)和自动拆箱(auto-unboxing). 我们知道,Java 语言拥有 8 个基本类型,每个基本类型都有对应的包装 ...

  2. 早期(编译器)优化--Java语法糖的味道

    1.泛型与类型擦除 泛型的本质是参数化类型的应用,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口和泛型方法.在泛型没有出现之前,只能通过 ...

  3. Java语法糖1:可变长度参数以及foreach循环原理

    语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...

  4. 转:【深入Java虚拟机】之六:Java语法糖

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/18011009 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家P ...

  5. Java语法糖设计

    语法糖 Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这 ...

  6. 深入理解java虚拟机(十二) Java 语法糖背后的真相

    语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是,在计算机语言中添加某种语法,这些语法糖虽然不会对语言 ...

  7. java语法糖---枚举

    java语法糖---枚举   在JDK5.0中提供了大量的语法糖,例如:自动装箱拆箱.增强for循环.枚举.泛型等.所谓“语法糖”就是指提供更便利的语法供程序员使用,只是在编译器上做了手脚,却没有提供 ...

  8. Java语法糖(二)

    语法糖之四:内部类 内部类:顾名思义,在类的内部在定义一个类.内部类仅仅是编译时的概念,编译成字节码后,内部类会生成单独的Class文件. 四种:成员内部类.局部内部类.匿名内部类.静态内部类. 1. ...

  9. 【深入Java虚拟机】之六:Java语法糖

    语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家Peter.J.Landin发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使 ...

  10. Java语法糖(一)

    概述 语法糖(Syntactic Sugar):主要作用是提高编码效率,减少编码出错的机会. 解语法糖发生在Java源码被编译成Class字节码的过程中,还原回简单的基础语法结构. 语法糖之一:泛型( ...

随机推荐

  1. MIT6.s081/6.828 lectrue1:Introduction and examples

    目前课程官网能够查到 2020,2021.2022 秋季的课程表,但是视频都是 2020 年录制的那一版 简单复习+回顾下自己的 OS 学习之旅 参考资料: 官网:https://pdos.csail ...

  2. 使用 Dockerfile 构建生产环境镜像

    传统部署的坑: 1202 年了,如果你连 Docker 都不知道是什么,我建议买一本书看看--或者谷歌一下,博客已经写烂了. 为什么有这篇文章,是因为我在真正做容器化改造的时候,发现公司生产环境存在大 ...

  3. zabbix 可计算监控项使用 last() 与 avg() 的区别

    使用zabbix的可计算监控项时遇到的问题 在agent异常退出的情况下,使用last()的监控项依然在产出数据! 分析解决 last()函数会跳过空值,取最后一个有效值计算.遍查文档,只有用avg( ...

  4. js高级之内存管理与闭包

    javacript中的内存管理 javascript中不需要我们手动去分配内存,当我们创建变量的时候,会自动给我们分配内存. 创建基本数据类型时,会在栈内存中开辟空间存放变量 创建引用数据类型时,会在 ...

  5. [glibc2.23源码]阅读源码&调试,找出free_hook-0x13分配失败的原因

    0x00 写在前面 发freebuf了:https://www.freebuf.com/articles/endpoint/373258.html 本次阅读源码是本人第一次,算是一个全新的开始.本次看 ...

  6. [ABC132D] Blue and Red Balls

    2023-01-16 题目 题目传送门 翻译 翻译 难度&重要性(1~10):3 题目来源 AtCoder 题目算法 dp 解题思路 因为蓝球的数量是固定的,题目让我们求,在取 \(i\) 次 ...

  7. 浅析 GlusterFS 与 JuiceFS 的架构异同

    在进行分布式文件存储解决方案的选型时,GlusterFS 无疑是一个不可忽视的考虑对象.作为一款开源的软件定义分布式存储解决方案,GlusterFS 能够在单个集群中支持高达 PiB 级别的数据存储. ...

  8. 《CTFshow-Web入门》03. Web 21~30

    @ 目录 web21 题解 原理 web22 题解 原理 web23 题解 原理 web24 题解 原理 web25 题解 原理 web26 题解 web27 题解 web28 题解 web29 题解 ...

  9. ATtiny88初体验(五):ADC

    ATtiny88初体验(五):ADC ADC模块介绍 ATtiny88单片机包含一个10bit分辨率的ADC模块,拥有8个通道,最大采样率15kSPS,转换时间14us.ATtiny88的ADC参考电 ...

  10. 我们能从PEP 703中学到什么

    PEP703是未来去除GIL的计划,当然现在提案还在继续修改,但大致方向确定了. 对于实现细节我没啥兴趣多说,挑几个我比较在意的点讲讲. 尽量少依赖原子操作的引用计数 没了GIL之后会出现两个以上的线 ...