深层解析int,Integer(new和不new)相互之间的比较

可以尝试以下两组比较的输出,看看是否符合预期答案:
第一组:

        int a =127;
        Integer b1=127;
        Integer b2=127;
        Integer c= new Integer(127);
        System.out.println(a==b1);
        System.out.println(a==c);
        System.out.println(b1==c);
        System.out.println(b1==b2);

第二组:

        int aa =128;
        Integer bb1=128;
        Integer bb2=128;
        Integer cc= new Integer(128);

        System.out.println(aa==bb1);
        System.out.println(aa==cc);
        System.out.println(bb1==cc);
        System.out.println(bb1==bb2);

答案揭晓:
第一组答案是
true
true
false
true
第二组答案是
true
true
false
false

其实如果只是想知道比较方法那很简单,我见过类似这样的总结(当然,这些结论都没错):
1.Integer与new Integer一定不会相等
2.两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
3.两个都是new出来的,则为false
4.int和integer(new或非new)比较,都为true

眼睛:我会了
脑子:不,你不会 !

整理一下思路:

问题1 :==比较的是什么?

地址。
不完全对,Java的数据类型可以分为基本数据类型(如int)和引用数据类型(如Integer),对于后者来说,双等号代表比较地址,而对于前者来说,双等号代表数值(value)比较。

基本数据类型 == 基本数据类型 比较值
引用数据类型 == 引用数据类型 比较地址

那么有了问题2,

问题2:基本数据类型==引用数据类型,比较的又是什么

当然是比较值了。。。
例如在一个方法当中,int a=1,这是一个局部变量,局部变量存储在哪里呢?栈当中(方法执行就是出栈和入栈的过程),而Integer呢?对象,当然在堆当中,不论如何也不会是同一个地址。当然这只是一方面的理解。
换个角度,int是基本数据类型,我要求比较值,Integer是引用数据类型,你想比较地址。总之我俩要么都是基本数据类型,要么都是引用数据类型才能进行比较。
Integer实际上包含了一个int类型的成员变量,可以把这个成员直接拿过来使用,所以相比int转化为Integer,Integer还是选择妥协,向下兼容,最终变成了比较值,所以有了“自动拆箱”这个词。

很好理解。。。

继续

问题3:两个直接赋值没有new的Integer怎么比较

建议到这里先看看文末的补充内容
没new也是引用类型,当然要比较地址
值在-128-127范围内的,如果值相同,就是同一个对象(值不同,地址当然更不同)
值不在-128-127范围内的,地址一定不同;

        Integer b1=127;
        Integer b2=127;
        Integer bb1=128;
        Integer bb2=128;
        System.out.println(b1==b2);//true
        System.out.println(bb1==bb2);//false        

Integer a=1 ;
1明明是一个int类型,你用Integer去声明它,应该报错才对,但是为了更好的进行数据转换,Java允许你这么声明,同时会将它自动装箱为Integer。在这种情况下, 如果a的值在-128-127范围内,就直接从默认的缓存中获取地址。
那如果不在这个范围内呢?就会new一个Integer对象(对此有疑问的直接跳到文章末尾看),即使两次值都一样,也是new出了两个对象,地址是不同的。
综上,不new直接复制的Integer,只要在-128-127这个范围内的,如果值相同,就是同一个对象(相同地址),值不同,地址也一定不同

问题4:两个new过的Integer怎么比较

两个对象,两个地址
不可能相同!!!
这个不作解释了。。。

问题5:直接赋值不new和new了赋值的怎么比较

例如:

        Integer b1=127;
        Integer c= new Integer(127);

前面讲到,不new的情况下(b1),如果值在-128-127范围内,会从默认缓存中直接获取引用(或者说地址),此时b1存放于常量池当中,如果值不在这个范围内,会new一个Integer对象并将其存放于堆当中。一个在常量池(方法区),一个在堆当中,地址是不可能相同的。

这是不new的情况,new了又是什么情况?

对比普通实体类,new一个对象会调用它的构造方法,开辟新的内存空间,我们刚才说不new直接赋值的情况下:
如果a的值在-128-127范围内,存放于常量池,而new出来对象在堆当中,地址肯定是不一样的;
如果a的值不在-128-127范围内,会new一个新的对象存放于堆当中,而直接new出来对象也在堆当中,但是这是两个new出的对象,地址一定是不一样的;故而说:
new过的Integer和没new过的Integer这两者用双等号比较,结果一定是false。

补充:
自动装箱:
Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法
比如 Integer i=1;这就完成了自动装箱
来看看这个valueOf方法写了什么:


    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    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的初始化之后的值分别是-128和127
在这里插入图片描述
Integer中的静态内部类 IntegerCache——缓存
IntegerCache默认缓存了-128-127范围的整型;
当执行Integer i = 一个值时,如果这个值在-128-127这个缓存的范围内,就直接引用缓存中对应的地址,如果值不在这个范围内,就会new integer()一个对象。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值