(详解)Java中Integer类的自动装箱、拆箱?看这一篇就够了

先看两个小栗子,整片博文围绕这个例子进行详解。

你可以先自己猜猜运行结果,然后再运行代码哦。这样理解会比较深刻。

先一个个来!!!!

栗子1:

public class IntegerTest {
    public static void main(String[] args) {
        Integer a = new Integer(11);
        Integer b = 11;
        int c = 11;
        System.out.println(a == c);
        System.out.println(a == b);
    }
}

 

===================================================

防止你这么快看到答案!

===================================================

true
false

你的结果是不是也是这个呢,如果不是也没关系,看完我下面所写的,会让你对Integer类的自动拆箱装箱有深刻的理解。

首先我来大概解释下这是怎么回事

1、a==c 为什么会是true呢?

因为c为基本类型,c(int)与a(Integer)比较时,c(Integer)会发生自动拆箱,a会拆箱成int来与c进行==比较。所以这里为true。

你听到这可能还是不理解拆箱,不用担心后面会讲到的,这只是大概告诉你发生了什么事,后面会用代码来证明的。

只有代码才是对的!

2、a==b为什么会是false呢?

因为a是Integer类型,b也是Integer类型,b这里进行了装箱操作,Integer b = 11,其实是等于Integer b = Integer.valueOf(3);

这里为什么会等于这个后面会讲到,你想想,Integer是引用类型,==是比较地址的,ab两个栈中的指向堆中的地址都不一样,所以他们是false。

==================================================

好了 重头戏来了

==================================================

这里你可以看着我来操作,当然也可以一起操作,这都很简单,只需要你有jdk+jre环境即可。

这里讲个题外知识,因为后面会用到,那就是javap

javap定义

javap是 Java class文件分解器,可以反编译(即对javac编译的文件进行反编译),也可以查看java编译器生成的字节码。用于分解class文件。

  1. 好了先创建一个IntegerTest.java文件
  2. 将上面的栗子拷贝进去
  3. 在当前目录 shift+鼠标右键打开powerShell窗口
  4. 然后输入两个命令 1、javac .\IntegerTest.java   2、javap -c IntegerTest
  5. 到这里就完事了,后面刷出一大堆javap -c 反汇编后的信息。咱们来阅读一下。

=============================================================

上面你看不懂没关系,我也不大懂,只需要有个javap指令集,将不懂的命令找出来解释就完事了 。

这里有个小福利,javap指令集的帖子

http://bbs.gupaoedu.com/forum.php?mod=viewthread&tid=295&extra=page%3D1

=============================================================

咱们来解析一下 咱们栗子中的每一行代码 对应指令集中的什么地方,根据咱们反汇编的class文件来分析jvm是如何运转的呢。

1、Integer a = new Integer(11);

咱们根据javap指令可以知道,invokespecial 根据编译时类型来调用实例方法,这个方法是什么呢,就是Integer的构造方法。

Integer的构造方法:

所以这行代码没什么好说的了,就是实例化一个Integer对象。设置value属性的值为11。主要是为了让大家熟悉下javap指令。

2、Integer b = 11;

重头戏来了,这里讲了装箱操作。

这里看到没有!!!invokestatic!他这里做了什么,他调用了Integer中的一个方法名叫做valueOf的静态方法。

咱们看看Integer的源码:

找到了,我来解释下这里说了什么,如果入参i的值-128<= i <=127就会从缓存中获取对象,Integer在堆中有很多个常用的对象,所以如果满足就直接引用地址就Ok了,否则将在堆中实例化一个新的对象。

这就是装箱操作,装箱操作调用了valueOf方法,这个是在编译期间就这样做的,所以Integer b = 3;是不是等同于Integer b = Integer.valueOf(3);啊!对吧。

我之前说过只有代码才是对的,才能让别人信服,不是泛泛而谈,说什么就是什么,而且 这样 一步一步分析,可以让你理解更加深刻,以后遇到问题也可以有个思路。

咱们继续讲。

3、int c = 11;

这个没啥好说的

就是将11压入操作数栈,然后将其store到变量c中,这里istore_3就是变量c,我以后还会分享JVM,会提到这方面的知识,希望大家关注我哦!

4、System.out.println(a == c);

这里讲的就是拆箱操作,咱们看看aload_1 从局部变量1中装载引用类型值,invokevirtual调度对象的实例方法,

这里看好!这里调用了这个Integer对象的什么方法啊,是不是intValue方法啊!

咱们看看源码:

这是个啥意思,是不是拆箱的时候将 Integer引用对象转换成了int基本类型啊,实际上a==c 是不是就是a.intValue() == c啊,这里也是jdk编译期间对其进行的操作。你看着是a==c其实class文件中是a.intValue()==c。

这就是拆箱操作。

5、System.out.println(a == b);

这个就是两个引用类型的比较了,==比较地址,他们两个地址不一样,指向堆中的实例化对象也不一样。

所以就是false了。

总结

Integer装箱操作:在编译期将Integer a = 3;这种格式的代码,编译成Integer a = Integer.valueOf(3);,这就是装箱操作。

Integer拆箱操作:在编译期将Integer转换成int类型,会调用int z = a.intValue()方法,拆箱操作在栗子中表现为,int类型与Integer类型进行==比较,此时Integer会进行拆箱操作。

到这里就讲完了,大家听了这么多,应该都听懂了吧。!!!(盲目自信!!!!)

还有一个栗子就留给大家帮我解答一下吧。

栗子2:

public class IntegerTest {
    public static void main(String[] args) {
        Integer a = 11;
        Integer b = 11;
        Integer c = 129;
        Integer d = 129;
        System.out.println(a == b);
        System.out.println(c == d);
    }
}

 

最后!!希望大家看完这篇文章后能够给我一点点feedback!!!谢谢大家!!!!!!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值