Java学习笔记 (十五) 自动拆箱与自动装箱

什么是自动拆装箱

  • 自动装箱: 就是将基本数据类型自动转换成对应的包装类.
  • 自动拆箱:就是将包装类自动转换成对应的基本数据类型。
For example :
  Integer a=1;  //自动装箱
  int b=a;     //自动拆箱

基本数据类型与包装类对应关系,如下:

基本数据类型包装类
booleanBoolean
byteByte
charCharacter
floatFloat
intInteger
longLong
shortShort
doubleDouble

自动拆装箱是怎么实现的

我们可以通过反编译去看他是如何实现的,反编译前代码:

    public static  void main(String[]args){

        Integer integer=1; //装箱
        int i=integer; //拆箱
        Double dou=2.0; //装箱
        double dou2=dou; //拆箱
        Float f=3f;//装箱
        float f2=f;//拆箱
        Byte b=4;//装箱
        byte b2=b;//拆箱
        Long lo=5l;//装箱
        long lo2=lo;//拆箱
        Character character=6;//装箱
        char c2=character;//拆箱
        Boolean bl=false;//装箱
        boolean bl2=bl;//拆箱
        Short s=8;//装箱
        short s2=s;//拆箱

    }

反编译后代码:
这里写图片描述

从上面反编译后的代码可以看出,自动装箱都是通过包装类的valueOf()方法来实现的.自动拆箱都是通过包装类对象的**Value()来实现的。

包装类比较数据大小是自动拆箱进行比较的吗

源码:

        Integer a=1;
        System.out.println(a==1?"等于":"不等于");
        Boolean bool=false;
        System.out.println(bool?"真":"假");

反编译后:
这里写图片描述
可以看到,包装类进行比较运算,是先进行拆箱成基本数据类型,然后进行运算的。

自动拆装箱有什么用

我从官网偷了个例子:

List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
    li.add(i);

为什么上面的代码不报错呢,因为编译时代码自动转换了一下,如下:

List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
    li.add(Integer.valueOf(i));

所以 li集合里面存的实际上是Interger对象,而不是基础数据类型。

  • 第一,方便使用,包装类中有很多方法,比如转换成其他数据类型的方法,等等
  • 第二, 多态,我们都知道,所有的类都继承了Object ,而基本数据类型没有继承,所有使用包装类可以使用多态这个特性,就像上面那个例子。

自动拆装的疑惑?

一、包装类对象为什么会相等

看,a==b 为true,c==d 为false

        Integer a=2;
        Integer b=2;

        Integer c=128;
        Integer d=128;

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

操作数都是对象,“==” 比较的是引用地址,都是自动装箱。应该都是false才是,为什么是a==b是true呢?
我们知道,自动装箱是通过valueOf()方法来实现的,源码如下:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

可以看出来,数值大小在low到high之间返回的是缓存中的对象,超出这个范围则是new 一个返回。low= -128 ;high如果不指定的话值为127;
很显然,2在这个范围,所以Integer.valueOf(2)的时候,返回的是缓存的对象,所以a和b其实是一个对象所以相等。
其他几个包装类中;Double与Float是直接new 一个对象返回的;Long,Short,Character与Integer类似,而Byte则是直接返回缓存中的对象,想一下Byte的取值范围就明白了;Boolean比较特殊,一共就两个值,如下:

这里写图片描述

二、什么时候会进行自动拆装箱

看一段我从某位大佬那里借鉴(偷)过来的代码:

        Integer a = 1;
        Integer b = 2;
        Integer c = 3;

        Long g = 3L;
        Long h = 2L;

        System.out.println(c==(a+b)); //1. true
        System.out.println(g==(a+b)); //2. true
        System.out.println(c.equals(a+b));//3. true

        System.out.println(g.equals(a+b)); //4. false
        System.out.println(g.equals(a+h));//5. true

仔细想下,为什么会这样呢?我来分析下,如果您认为我分析有误或者有疑问欢迎联系我。

  • 1、为什么c==(a+b) 为true?
    是因为,a+b 是进行算术运算,上文提到过,算术运算时,会拆箱成基本数据类型进行运算,那么a+b的结果也是基本数据类型,而包装类类型进行==比较时,如果有一方是基本数据类型,那么包装类类型会进行拆箱。所以c==(a+b) 比较的是数值是否相等。 结果为true
  • 2、为什么g==(a+b) 为true?
    同1。
  • 3、c.equals(a+b) 为什么为 true?
    首先放一段Integer.eqquals()的源码:
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

看了上面的源码就很好理解了,a和b都是Integer类型,拆箱算术运算结束后结果也是int 类型,然后equals需要的是对象,所以这里会进行装箱,还是Integer类型,然后类型判断结果为true,比较的是数值,所以结果为true。
- 4、g.equals(a+b) 为什么是false呢?
g是Long类型,我们看下Long的equals()方法;

    public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }

看了源码很容易就知道为什么了,上面说过a+b结果为int类型,在这里自动装箱也是对应的Integer类型,Integer 类型不属于Long类型,结果为false,直接返回false,
- 5、g.equals(a+h)为什么为true?
相信你已经很明白了为什么了。

下面放出反编译后的代码,很容易就看出哪里进行了拆箱装箱。

这里写图片描述

参考资料:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值