必考:从字节码层面看自动拆装箱的原理

2023-11-16 13:02:25 浏览数 (1)

将程序视点设为星标精品文章第一时间阅读

大家好,欢迎来到程序视点!我是小二哥。

上一篇文章中,我们分享包装类的缓存机制时,提到了自动装箱的问题。今天我们就重点分享自动装箱的原理,及其相关的知识点(笔试必考)!

前面介绍过,把基本类型转换成包装类型的过程叫做装箱(boxing)。反过来,把包装类型转换成基本类型的过程叫做拆箱(unboxing)

我们来举个例子:

代码语言:javascript复制
Integer i = 10;  //装箱
int n = i;   //拆箱

上面两行代码,就执行了自动装箱和自动拆箱的过程。有小伙伴可能就说了,“你说装箱就是装,拆箱就是拆呀?怎么证明呢?”

最好的证明,就是看系统运行时真正执行了什么?我把上面它们执行的字节码粘贴下:

大家只需看字节码片段中,红框的内容就好。几个简单的单词,大家应该都熟悉。invoke static java/lang/Integer.valueOf (I):调用静态方法。哪个静态方法呢?Java的lang包下Integer类的静态方法,方法名是valueOf(I),其中I就是传入的参数。那么,执行第一句代码的时候,系统为我们执行了:

代码语言:javascript复制
Integer i = Integer.valueOf(10);

同理,执行第二句代码的时候,系统为我们执行了:

代码语言:javascript复制
int n = i.intValue();

也就是说,自动装箱是通过 Integer.valueOf() 完成的;自动拆箱是通过 Integer.intValue() 完成的。

必考点

理解了原理之后,我们来看看常考的知识点。

基本类型和包装类型进行 == 比较,包装类型会自动拆箱,直接和基本类型比较值
代码语言:javascript复制
int a = 9;
Integer b = 9;
System.out.println(a == b);

由于包装类型会自动拆箱后再比较,上述代码的结果为 true。

自动装箱时的缓存机制

当需要进行自动装箱时,如果数字在 -128 至 127 之间,会直接使用缓存中的对象,而不是重新创建一个对象。Integer 缓存源码:

代码语言:javascript复制
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i   (-IntegerCache.low)];
    return new Integer(i);
}

主要是这个IntegerCache.cache数组中缓存着的。大家可以翻阅上一篇文章

举个例子:

代码语言:javascript复制
Integer a = 100;
Integer b = 100;
System.out.println(a == b);

这里的答案是:true

代码语言:javascript复制
Integer a = 199;
Integer b = 199;
System.out.println(a == b);

而这时的答案是:false。因为 199 不在 -128 至 127 范围之内,所以 new 出来了两个 Integer 对象。既然是new出来的,那就会在堆空间中产生不同的对象,不同的对象在进行 == 比较的时候,比较的是内存中的地址,不同对象的内存地址肯定不一样,所以返回false。

自动拆装箱的高阶考点

直接来看题:

代码语言:javascript复制
Integer a = 9999;
Integer b = 9999;
System.out.println(a   1 == b   1);

先别看下面的答案,看你能做对不?

这2个包装类型的Integer在运算时会自动拆箱,变成2个基本数据类型的比较,相当于在判断:

代码语言:javascript复制
a.intValue()   1 == b.intValue()   1

而两个基本数据类型比较时只看数值大小,故结果为true。

好啦!今天的内容就到这里啦!希望以后面试到自动拆装箱的比较问题,大家都能手到擒来~

0 人点赞