Java自动装箱和自动拆箱

Java自动装箱和自动拆箱

Java1.5以后,为了进一步解放程序员的双手,Java引用了自动装箱(AutoBoxing)和拆箱(UnBoxing)。


定义:

自动装箱:Java自动将原始数据类型转化为相应的包装类对象,例如,把int转化为Integer。
拆箱:自动装箱的反过程,相应的包装类对象转化为原始数据类型,例如,把Integer转为int。

内置类型和包装器
内置类型包装器类型
booleanBoolean
charCharacter
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
voidVoid


实现机制:

     当发生自动装箱时,编译器自动调用了valueOf()方法,得到相应的包装器对象,当发生拆装时,编译器自动调用了xxxValue()方法(例如IntValue,LongValue等)。
  • 如若想确认是否调用了相应的方法,可以在相应的位置设置断点,debug一下就能看到进入相应的方法。

  • 使用java自带的javap反编译工具也能看得出来。

性能的比较:

自动装箱和拆箱是编译器分别通过自动调用valueOf()和xxxValue()来实现的,使用包装器类型和直接使用基本数据类型上就会有一性能的差距。
Long sum = new Long(0);//sum是包装器Long
for(long i=0;i<Integer.MAX_VALUE;i++){
     sum += i;
}
windows7, I5的处理器,4G的内存,时间:11S

long sum = new Long(0);//sum是基本类型long
for(long i=0;i<Integer.MAX_VALUE;i++){
     sum += i;
}
windows7, I5的处理器,4G的内存,时间:1S

从结果可以看出,时间上相差10秒,差距还是不小的。

常见面试题目:

题目1:

public class App {
        public static void main(String[] args) {
              Integer i1 = 127;
              Integer i2 = 127;
              Integer i3 = 128;
              Integer i4 = 128;
              
              System. out.println(i1 == i2);
              System. out.println(i3 == i4);
       }

}
程序的输出是什么呢,如果你的答案是true,true的话,以下就值得这你留步了。程序的输出是true,false。
我们先看源代码:
public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache. high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
在Integer里,valueOf是以上这样实现的,为了降低内存占用和垃圾回收的成本,类库里增加了一个cache,保存常用的int包装器对象(-128~127),当数值在这个范围时,就从cache里取出对象,所以i1和i2指同一个内在块,输出就为true。而i3和i4的值大于127,就不会在这个cache里取值,重新new一个对象,因此不是同一个内存块,输出就为false。

Integer和Long都是使用了cache机制,所以在-128-127之间,比较都为true,但是Ingeger的cache大小可以通过参数来改变,但是Long却不行。

-Djava.lang.Integer.IntegerCache.high=300
-Djava.lang.Integer.IntegerCache.low=-300

Boolean也使用了cache的机制,源代码如下:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);

public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

题目2:

public class Main {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Long g = 3L;
        Long h = 2L;

        System.out.println(c==(a+b));//1
        System.out.println(c.equals(a+b));//2
        System.out.println(g==(a+b));//3
        System.out.println(g.equals(a+b));//4
        System.out.println(g.equals(a+h));//5
    }
}

输出:
true
true
true
false
true

  1. a拆箱,b拆箱,相加结果为int,c拆箱,int和int相比较.
  2. a拆箱,b拆箱,相加结果为int,方法equals的参数是Object,所以int又要装箱,引用比较,又因为数据3在cache里,所以为true.
  3. a拆箱,b拆箱,相加结果为int,转化为long型,g拆箱,数值相比较,为true.
  4. a拆箱,b拆箱,相加结果为int,方法equals的参数是Object,所以int又要装箱为Integer,Long和Integer比较,所以为false.
  5. a拆箱,b拆箱,相加结果为long,方法equals的参数是Object,所以要装箱为Long,Long和Long相比较,所以为true。

从以上测试中,可以得出以下结论:
当基本数据类型和包装器类型做'=='运算时,包装器类型会拆箱为基本数据类型,再做‘==’运算。


网上博客的错误:

在进行学习时,参考了网上的一些博客,发现了一些错误,指了出来,减少大家的错误知识点。

<del>当包装器类型进行“==”比较时,i1会调用Integer.valueOf自动装箱基本数据类型为包装器类型。</del>

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2);

看到这个时,在想,i1已经是Integer对象了,而valueOf的参数是int型的,那要怎么调用呢,后来通过DEBUG,证明
这句话是错误的,调用valueOf的时间是在初始化i1时,而不是在比较时。

<del>会自动拆箱(会调用intValue方法)</del>
Integer c = 3;
Integer d = 3;
System. out.println(c==d);

参考:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值