【JVM类加载及字节码技术】编译期处理-语法糖-构造、泛型、拆装箱(一)

前言

一、默认构造函数

  • 1.案例代码
  • 2.编译优化后

二、自动拆装箱

  • 1.案例代码
  • 2.编译优化后

二、泛型集合取值

  • 1.案例代码
  • 2.字节码文件

前言

语法糖:其实就是指java编译器把 .java 源文件编译为 .class 字节码的过程,自动生成和转换的代码,主要是为了减轻程序员的负担,算是java编译器给我们的额外福利。

注意,以下代码的分析,借助了javap工具,idea的反编译功能,idea插件jclasslib等工具,编译器转换的结果就是class字节码,只是为了便于阅读,给出几乎等价的Java源码方式,并不是编译器还会转换出中间的Java源码。

提示:以下是本篇文章正文内容,下面案例可供参考

一、默认构造函数
1.案例代码
代码如下:

public class Candy1 {

}

2.编译优化后
代码如下:

public class Candy1 {
//这个无参构造器是java编译器帮我们加上的
public Candy1() {
//即调用父类 Object 的无参构造方法,即调用 java/lang/Object." <init>":()V
super();
}
}

原始代码在经过编译优化后会添加一个无参构造,这就是默认构造方法。

在默认构造方法中会调用父类的无参构造。

二、自动拆装箱
基本类型和其他包装类型的相互转换过程,称为拆装箱。

在JDK5以后,它们的转换都可以在编译器自动完成。

1.案例代码
代码如下:

public class Demo2 {
public static void main(String[] args) {
Integer x = 1;
int y = x;
}
}

2.编译优化后
代码如下:

public class Demo2 {
public static void main(String[] args) {
//基本类型赋值给包装类型,称为装箱
Integer x = Integer.valueOf(1);
//包装类型赋值给基本类型,称谓拆箱
int y = x.intValue();
}
}

在代码经过编译优化后,可以发现会通过添加一些固定的代码,减少程序员负担。

在拆箱和装箱过程中,因为代码都是固定不变,所以可以进行优化。

二、泛型集合取值
泛型也是在JDK 5 开始加入的特性,但Java在编译泛型代码后会执行泛型擦除,即泛型信息在编译为字节码之后就丢失了,实际的类型都当作了Object类型来处理。

1.案例代码
代码如下:

public class Demo3 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(10);
Integer x = list.get(0);
}
}

2.字节码文件
字节码如下:

Code:
stack=2, locals=3, args_size=1
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: bipush 10
11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;


//这里进行了泛型擦除,实际调用的是add(Objcet o)
14: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z

19: pop
20: aload_1
21: iconst_0
//这里也进行了泛型擦除,实际调用的是get(Object o)
22: invokeinterface #6, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;


//这里进行了类型转换,将Object转换成了Integer
27: checkcast #7 // class java/lang/Integer

30: astore_2
31: return

在上图字节码文件中,我们可以重点关注14以及27行指令,分别对应擦除,以及转换。

14行指令这里进行了泛型擦除,实际调用的是add(Objcet o)。

//这里进行了泛型擦除,实际调用的是add(Objcet o)
14: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z

27行指令这里进行了类型转换,将Object转换成了Integer
//这里进行了类型转换,将Object转换成了Integer
27: checkcast #7 // class java/lang/Integer

在调用get函数取值时,有一个类型转换的操作:

Integer x = (Integer) list.get(0);

如果要将返回结果赋值给一个int类型的变量,则还有自动拆箱的操作:

int x = (Integer) list.get(0).intValue();

posted @ 2022-03-03 16:06  方东信  阅读(41)  评论(0编辑  收藏  举报