Integer缓存那点小事儿

这篇博客详细探讨了Java中Integer缓存的机制,解释了Integer i=200;和new Integer(200)之间的区别。博主通过源码分析指出,对于-128到127之间的数值,Integer会从缓存中获取对象,否则会在堆上新建。文章通过实例展示了不同情况下Integer对象的比较结果,并提到了其他类似做法如Byte、Short等的缓存机制。

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

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

Integer 面试中我们经常被问到,另外工作中我们也经常遇到Integer的比较,所以今天来快速总结下这个知识点。

1. Integer i=200; 会发生什么?

首先我们假设声明了两个局部变量

java Integer i=200; Integer j=100;

事实上,Java最终的逻辑是不管你后边的数是多少,最终都会调 Integer.valueOf(i);来将给定的数值,进行 装箱 操作,但是里边会判断,就是如果给定数值 i

  • 是在-127-128之间的数值,那么将会从一个Integer类型的缓存数组中 拿到指定位置(即index是给定数值的)对应的Integer对象, 如果给定数值i不在 -127-128范围内,那么
  • 将会在堆上开辟空间,new一个Integer对象出来

空口无凭,我们使用命令反汇编一下,看看到底是是不是会像上边说的那样; 执行命令:

Javap -p -v -c target/test-classes/com/xzll/test/mianshi/IntegerCacheTest.class

结果如下: image.png

2. IntegerCache初始化源码&&valueOf简析

我们看下这个逻辑,Integer类源码如下:

```java public final class Integer extends Number implements Comparable { private static class IntegerCache { //下界 static final int low = -128; //上界,可通过 -XX:AutoBoxCacheMax=size 来调整大小,但是不能超过Inter.MAX,并且小于127的话,就还是取127 static final int high; //这个就是存储Integer对象的数组了 static final Integer[] cache; static Integer[] archivedCache;

static {
    // high value may be configured by property
    int h = 127;
    String integerCacheHighPropValue =
        VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    //一堆判断,判断是用你配的?还是默认的?,上限值
    if (integerCacheHighPropValue != null) {
        try {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        } catch( NumberFormatException nfe) {
            // If the property cannot be parsed into an int, ignore it.
        }
    }
    high = h;

    // Load IntegerCache.archivedCache from archive, if possible
    VM.initializeFromArchive(IntegerCache.class);
    int size = (high - low) + 1;

    // Use the archived cache if it exists and is large enough
    // 新建一个Integer数组,初始值为-128, -127, ..., 0, 1, 2, ..., 127
    if (archivedCache == null || size > archivedCache.length) {
        Integer[] c = new Integer[size];
        int j = low;
        for(int k = 0; k < c.length; k++)
            c[k] = new Integer(j++);
            //赋值给 archivedCache变量
        archivedCache = c;
    }
    //赋值给 cache变量
    cache = archivedCache;
    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
}

private IntegerCache() {}

}

public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)];//不new object,而是直接从cache中读出object返回 return new Integer(i);//new 一个Integer对象返回 }

} ```

上边代码比较简单,我们不过多展开了

3. 演示一下各种对比以及结果:

```java public static void main(String[] args) {

int i1 = 200; Integer i2 = 200; System.out.println("i1 == i2:结果:" + (i1 == i2) + ",// int和new出来的Integer (因为200不在(-127-128)区间,所以会new对象 )比较,i2会自动拆箱 所以会变成两个int的比较");

Integer i3 = 200;//编译后,此处变为 -> Integer i3 = Integer.valueOf(200); 也就是说不会从IntegerCache中获取,而是new了一个对象 Integer i4 = 200; System.out.println("i3 == i4:结果:" + (i3 == i4) + ",// 由于200不在缓存 -127-128之间,所以此处是两个对象的比较,i3内存地址:" + System.identityHashCode(i3) + " ,i4内存地址:" + System.identityHashCode(i4));

Integer i15 = new Integer(100); Integer i16 = new Integer(100); System.out.println("i15 == i16:结果:" + (i15 == i16) + ",// i15和i16是new的两个对象,i15内存地址:" + System.identityHashCode(i15) + " ,i16内存地址:" + System.identityHashCode(i16));

Integer i17 = 100; System.out.println("i15 == i17:结果:" + (i15 == i17) + ",// 由于 i15是new的对象,i17是从Integer缓存数组中拿的对象,两个都是对象,i15内存地址:"+System.identityHashCode(i15)+",i17内存地址:"+System.identityHashCode(i17));

Integer i18 = 100; System.out.println("i17 == i18:"+"结果:" + (i17 == i18) + ",// 由于100 在缓存 -127-128之间,所以此处是两个相同对象的比较(因为都是从数组中拿的同一个index位置的Integer对象),i17内存地址:" + System.identityHashCode(i17) + " ,i18内存地址:" + System.identityHashCode(i18));

int i100=100; System.out.println("i5==i100:结果:"+(i15==i100)+",// 由于i100是基础类型,和从Integer缓存中拿出来的i17(Integer对象比较)比较,i17会自动拆箱,结果自然是true"); } ```

输出:

i1 == i2:结果:true,// int和new出来的Integer (因为200不在(-127-128)区间,所以会new对象 )比较,i2会自动拆箱 所以会变成两个int的比较 i3 == i4:结果:false,// 由于200不在缓存 -127-128之间,所以此处是两个对象的比较,i3内存地址:706197430 ,i4内存地址:1325808650 i15 == i16:结果:false,// i15和i16是new的两个对象,i15内存地址:510464020 ,i16内存地址:1987083830 i15 == i17:结果:false,// 由于 i15是new的对象,i17是从Integer缓存数组中拿的对象,两个都是对象,i15内存地址:510464020,i17内存地址:1632492873 i17 == i18:结果:true,// 由于100 在缓存 -127-128之间,所以此处是两个相同对象的比较(因为都是从数组中拿的同一个index位置的Integer对象),i17内存地址:1632492873 ,i18内存地址:1632492873 i5==i100:结果:true,// 由于i100是基础类型,和从Integer缓存中拿出来的i17(Integer对象比较)比较,i17会自动拆箱,结果自然是true

(idea运行)附图如下:

image.png

3.1 做个小总结

  • 无论如何,Integer i=xxx; 与new Integer(xxx) 不会相等。不会经历拆箱过程
  • 两个都是非new出来的Integer对象(即Integer i=xxx ),如果xxx 在-128到127之间,则是true,否则为false
  • 两个都是new出来的,都为false
  • int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比

4. 事实上,不仅Integer这么做,其他也有类似做法,如下

  • 有 ByteCache 用于缓存 Byte 对象
  • 有 ShortCache 用于缓存 Short 对象
  • 有 LongCache 用于缓存 Long 对象
  • 有 CharacterCache 用于缓存 Character 对象

Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。

可以看出来jdk的大佬们是多么的追求极致!

一天一小步,一年一大步!


ps:今晚是通宵上线的一晚,请bug远离我~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值