Java中的自动拆装箱

Java中的自动拆装箱


    Java语言中,基本类型和它对应的封装类型直接可以相互复制,共同参与运算。其实,经过编译后并不是直接使用不同的类型来进行赋值和运算,而是采用了自动拆装箱的方式把数据类型进行了变化。自动拆装箱只是JDK语法糖技术中的一个。如下的代码是可以通过编译并且成功运行的:
    
    public void assignment(){
        int a = 1;
        Integer b = a;
        Integer c = 1;
        int d = c;
        int e = a + b;
        Integer f = c + d;    

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

通过javap命令,的这个方法的虚拟机指令序列
 public void assignment();
    Code:
       0: iconst_1
       1: istore_1
       2: iload_1
       3: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6: astore_2
       7: iconst_1
       8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: astore_3
      12: aload_3
      13: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      16: istore        4
      18: iload_1
      19: aload_2
      20: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      23: iadd
      24: istore        5
      26: aload_3
      27: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      30: iload         4
      32: iadd
      33: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      36: astore        6
      38: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      41: iload         5
      43: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
      46: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      49: aload         6
      51: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      54: return

   从指令序列的第三行和第八行可以看出,把int类型的值赋给Integer类型的变量经过编译后,变成了先利用装箱方法Integer.varlueOf()把int类型包装成Integer类型,然后再复制给Integer类型的变量。
   
    第13行的指令意味着,把Integer类型的值赋值给int类型变量需要利用拆箱方法Integer.intValue()先得到int类型的值,然后再赋值给int类型的变量。

   第18到24行代表代码中的int e = a + b。Integer类型的变量和int类型的变量相加,Integer变量会先转换成int类型,再进行相加运算。得到的结果是int类型。


    Java不通于c语言,不能重载加减乘除等运算符。所以在进行元素时,包装类型都需要拆箱成基本类型才能运算。如果包装类型为null,则会报出空指针异常。

    但是,不论包装类型还是基本类型都可以通过==操作符来比较两个变量是否相等,包装类型可以使用equeals方法比较两个对象。那么,包装类型和基本类型在比较时都会进行哪些类型转换呢?看下面的实验

   public void compare(){
        Integer a = 129;
        Integer b = 129;
        int c = 129;
        Integer e = 127;
        Integer f = 127;

        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a.equals(c));
        System.out.println(e == f);
    }

  要想知道都在哪些地方做了类型转换,还是需要看看编译后的指令,只不过指令代码有点长不做粘贴了。最后的结论是,比较a和c时,把a拆箱成了int值。也就是==比较包装类和基本类型时,把包装类型拆箱成了基本类型。

通过上面的实验可以得出下面的结论:
1,包装类型和基础类型相互赋值时,利用对应的拆箱或装箱方法把右值转化成左值的类型。
2,包装类型和基础类型在一起混合运算(包括==),则把封装类型拆箱成基本类型
3,equals方法是包装类型特有的方法(继承自Object),基本类型不能利用这个方法比较。

  这里还有一个有意思的地方,a和b是不相等的,而e和f是相等的。产生这个现象的原因是,Integer类型利用了缓存技术,在其内部缓存了从-128到127范围内的数据,每当需要这个范围内的对象的时候就会返回缓存池中的对象。那么,如果直接new两个缓存范围内的Integer对象,通过==判断它们会相等吗?不要想的那么复杂,都new了,怎么会相等。==操作符比较的是对象在内存中的位置,除非是同一个对象,不然一定不相等。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值