java装箱与拆箱原理_《深入理解java虚拟机》自动装箱拆箱实例

先上机实验一次,例子在《深入理解java虚拟机》P274面

代码为:

public class Test {

public static void main(String[] args)

{

Integer a = 1;

Integer b = 2;

Integer c = 3;

Integer d = 3;

Integer e = 321;

Integer f = 321;

Long g = 3l;

System.out.println(c==d); //true 结果1

System.out.println(e==f); //false 结果2

System.out.println(c.equals(a+b)); //true 结果3

System.out.println(g==(a+b)); //true 结果4

System.out.println(g.equals(a+b)); //false 结果5

}

}

输出结果在代码注释部分,

我们来看看

public class Test

{

public Test()

{

}

public static void main(String args[])

{

Integer a = Integer.valueOf(1);

Integer b = Integer.valueOf(2);

Integer c = Integer.valueOf(3);

Integer d = Integer.valueOf(3);

Integer e = Integer.valueOf(321);

Integer f = Integer.valueOf(321);

Long g = Long.valueOf(3L);

System.out.println(c == d);

System.out.println(e == f);

System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));

System.out.println(g.longValue() == (long)(a.intValue() + b.intValue()));

System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));

}

在分析前,我们先看看 == 和equals 的区别:

== 在操作数是基本数据类型时,是比较值是否相等,在操作数是引用类型时,比较的是是否指向堆中同一个对象。

equals是object的普通方法,object是所有类的基类,不同的类,重写equals的方法不同,基本数据类型当然没这个方法咯,在引用类型的时候,比较的东西得你自己去重写,你想比较神马就比较神马,Integer的equals就是比较的被赋予的值(一般都是比较这个,String也是)。

Integer的equals源代码如下:

public boolean equals(Object obj) {

if (obj instanceof Integer) {

return value == ((Integer)obj).intValue();

}

return false;

}

—————————————————-分割线—————————————————

System.out.println(c==d); //true

System.out.println(e==f); //false

上面2句代码,第一句,2个对象比较,比较的是c和d是否指向同一个Integer对象,结果是true(我本以为是false),那么就是说指的是同一个对象咯?奇怪啊,不会吧,不是生产了2个Integer对象吗?难道在装箱的时候,搞什么鬼了?我们看看装箱代码(自动装箱其实就是编译器编译的时候,自动帮你把int变成Integer对象,调用的是Integer的静态方法valueOf(),看反编译过来的代码就可以看出):

public static Integer valueOf(int i) {

if(i >= -128 && i <= IntegerCache.high)

return IntegerCache.cache[i + 128];

else

return new Integer(i);

}

上面的代码可以看出,当你调用这个方法,把int变成Integer的时候,是有规则的,当你的int的值在-128-IntegerCache.high(127) 时,返回的不是一个新new出来的Integer对象,而是一个已经缓存在堆中的Integer对象,(我们可以这样理解,系统已经把-128到127之间的Integer缓存到一个Integer数组中去了,如果你要把一个int变成一个Integer对象,首先去缓存中找,找到的话直接返回引用给你就行了,不必再新new一个)。这样我们就能解释为什么c和d是指向同一个对象了(c和d的int值是3),而e和f则引用的2个不同Integer对象,因为他们的值是321。

作者说

“包装类的==操作在没有遇到算术运算的情况下,不会自动拆箱”从结果1、2、4的反编译代码可以得出结论,(其实,我们可以从另一个方面解释为什么不会自动拆箱。当==2边是包装类的时候,其实包装类就是对象,比较的是2个对象引用是否指向同一个对象,如果2边有一个是基本数据类型的话,那么就是比较值大小,这个优先级更高,既然是比较值大小,那么自然另一边的包装类就要拆箱成基本类型进行比较值大小了)

“它们的equals方法不会处理数据类型转型的关系” 从结果4、5可以看出,因为如果会处理数据类型转换的话,那么5的结果就是true了。看下long的equals的源代码:

public boolean equals(Object obj) {

if (obj instanceof Long) {

return value == ((Long)obj).longValue();

}

return false;

}

首先就判断一下,你是不是Long类型,如果不是,比都别比 ,直接返回false。

System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));

你看上面那行代码,a首先拆箱,b也拆箱,然后相加,再将结果装箱成Integer,Integer当然不是long型了,因为它们的equals方法不会处理数据类型转型的关系(作者已经说了)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值