Intger和int做比较的坑

本文探讨了Java中Integer对象与int值比较时的细节,重点在于Integer的缓存特性。从-128到127的Integer对象会被缓存,导致自动装箱和拆箱时的特定行为。通过示例代码展示了当比较值超出默认缓存范围时,对象引用不相等。同时介绍了如何通过JVM启动参数调整Integer缓存范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Integer 缓存(IntegerCache)是 Java 5 中引入的一个有助于节省内存、提高性能的特性

废话不多说,看一个栗子

/**
 * @author :Vimonster
 * @time : 2019/12/19 10:41
 * @slogan: 任时间再怎样低头呢喃,也要不挥泪后风雨兼程
 * @description:
 *
 * 关于Integer 和 int 的一些注意事项
 *
 */
public class IntegerBug {


    public static void main(String[] args) {

        test1();
        test2();
    }

    /**
     * 比较值问题
     *
     */
    private static void test1(){

        Integer a = 110;
        int b = 110;
        Integer c = new Integer(110);

        System.out.println(a == b); //true 此处相等 应为Integer在和int比较时会自动拆箱 变为int 此处a自动拆箱为int类型 对象的比较也就变成了值的比较
        System.out.println(a == c); //false 因为c使用了new对象 c的值其实在堆空间 而 a 的值在常量池 两个都是对象 对象地址不一样 所以是false
    }


    /**
     *
     * -128与127之间,Integer会自动存在IntegerCache.cache 直接从内存中去取,不在这个范围则会new新对象
     *
     */
    private static void test2(){
        int a = 127;
        int b = 127;
        Integer c = 127;            //编译的时候 翻译为:Integer c = Integer.valueOf(127);
        Integer d = new Integer(127);
        Integer e = 127;
        System.out.println(a == b); //true
        System.out.println(a == c); //true
        System.out.println(c == d); //false
        System.out.println(a == d); //true
        System.out.println(c == e); //true  c 和 e 实际上是同一个对象。所以使用”==“比较返回true。
        test3();
    }

    private static void test3(){
        int a = 128;
        int b = 128;
        Integer c = 128;
        Integer d = new Integer(128);
        Integer e = 128;
        System.out.println(a == b); //true
        System.out.println(a == c); //true
        System.out.println(c == d); //false
        System.out.println(a == d); //true
        //todo 注意 java6之后如果不修改 XX:AutoBoxCacheMax=size 此处是false
        // 如果修改 XX:AutoBoxCacheMax=size 使其size大于128此处就为true
        // !!!java6之后 IntegerCache.high 可以修改  !!!java6之后 IntegerCache.high 可以修改 !!!java6之后 IntegerCache.high 可以修改
        System.out.println(c == e); //false //128超出了Integer缓存范围 c 和 e 都是new 出来的对象
    }

}

java6之后在不通过JVM启动参数修改IntegerCache值的范围的前提下,处于节省内存的考虑,JVM会缓存-128到127的Integer对象 即:IntegerCache.low=-128 IntegerCache.high=127,也就是在IntegerCache=[-128, 127]

  • 自动装箱:

将一个int赋值给一个Integer,会发生自动装箱,装箱过程系统对int类型的值X执行了Integer.valueOf(X);

Integer a = 10;

//在编译时 上述代码被翻译为下面的代码

//10在[-128, 127]范围内所以直接从缓存池返回10对应的Intger对象,否则将会new一个新的Integer赋值给a

Integer a = Integer.valueof(10); 

  • 自动拆箱:

一个Integer对象和一个int值作比较,会发生自动拆箱,拆箱过程系统对Integer类型的对象X执行了X.intValue();

Integer a = 110;
int b = 110;
//在Integer对象a 和 基本类型 b 做比较时 a 会做这样的转化 a = a.intValue(); 变成一个int类型的值 
// 再和b做比较 此时变成了数值之间的比较
System.out.println(a == b);


回头再看test1方法

Integer a = 110;

这一行简单的代码,其实发生了很多事。 110是基本类型 赋值 给一个Intger类型的对象 a  ,其实在编译过程中,由于自动装箱, 这行代码会翻译成 如下:

Integer c = Integer.valueOf(110);

我们看一下jdk1.8的Integer.valueOf(x)的源码

/**
*
* 将基本类型int 处理完后 返回Integer对象的过程叫做自动装箱
*/
public static Integer valueOf(int i) {
        //判断int类型的值i 是否介于Integer缓存池的最大值和最小值之间
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            //如果i在Integer缓存池的范围 直接从缓存池拿装箱后的对象
            return IntegerCache.cache[i + (-IntegerCache.low)];
        //如果i不在缓存池范围内 new一个新的对象返回
        return new Integer(i);
    }

知道了上述源码后,再来看test3方法中的 c == e 为什么返回是false了


Integer c = 128; // c不在[-128, 127]范围内 根据上述源码得知装箱过程中 c = new Integer(128);
Integer e = 128; // e不在[-128, 127]范围内 根据上述源码得知装箱过程中 e = new Integer(128);
//c是一个new 出来的对象 e是也是一个new出来的对象 在堆内存中对应的是两个对象 所以此处为false
System.out.println(c == e); //false
  • 如何修改IntegerCache的范围

都说Integer缓存池的大小在-128和127之间,也就是IntegerCache.low=-128  IntegerCache.high=127  

严格来说应该是如果自己不指定缓存值的范围, 默认的是这样, 什么缓存池的范围还可以自己指定???

是的, 你没听错,在java6之后, 可以使用JVM的启动参数设置最大值 (通过JVM的启动参数

-XX:AutoBoxCacheMax=size 进行修改)

不信我用idea来演示一下,idea修改JVM启动参数

1.idea右上角如图中所示 点击一下有个下拉框 点击Edit Configurations..选项 弹出框如图二所示

2.在该页面的VM options选项中填写-XX:AutoBoxCacheMax=256 设置Integer缓存值最大值为256

此时再次运行上面的test3 你会发现 c == e 会变成true 因为此处的128在新设置的Integer缓存池-128~256范围之内,所以在进行装箱操作的时候,是直接从Integer缓存池中拿的对象, c和e都是从缓存池中拿的同一个对象, 所以c == e 是true

private static void test3(){
        int a = 128;
        int b = 128;
        Integer c = 128;
        Integer d = new Integer(128);
        Integer e = 128;
        System.out.println(a == b); //true
        System.out.println(a == c); //true
        System.out.println(c == d); //false
        System.out.println(a == d); //true
        //todo 注意 java6之后如果不修改 XX:AutoBoxCacheMax=size 此处是false
        // 如果修改 XX:AutoBoxCacheMax=size 使其size大于128此处就为true
        // !!!java6之后 IntegerCache.high 可以修改  !!!java6之后 IntegerCache.high 可以修改 !!!java6之后 IntegerCache.high 可以修改
        System.out.println(c == e); //true//128未超出了Integer新设置的最大缓存256 c 和 e 是同一个对象 是直接从缓存池中拿到的对象
    }

所以从严格意义上来说 在java6之后, 在不通过JVM启动参数修改Integer缓存池的范围值时, 系统的Integer缓存池的大小才是在-128和127之间。

 

上述就是Integer和int之间作比较常见的一些问题喽 !!!

 

如果觉得生活很迷茫,就只管埋头变强、

                                                                                                                                                      2019-12-19   --于南京

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值