Java中Integer的缓存池是怎么实现的?

开始介绍之前,希望大家能想一想下面这串代码运行出来的结果是什么?

java 复制代码
public class IntegerCacheTest {

    public static void main(String[] args) {
        fun1();
        fun2();
        fun3();
        fun4();
    }

    public static void fun1(){
        Integer num1 = -129;
        Integer num2 = -129;
        System.out.println(num1 == num2);
    }

    public static void fun2(){
        Integer num1 = -128;
        Integer num2 = -128;
        System.out.println(num1 == num2);
    }

    public static void fun3(){
        Integer num1 = 127;
        Integer num2 = 127;
        System.out.println(num1 == num2);
    }

    public static void fun4(){
        Integer num1 = 128;
        Integer num2 = 128;
        System.out.println(num1 == num2);
    }
}

-129和-129的Integer对象,相不相等?使用基本数据类型int定义的值肯定相等,但是Integer是引用数据类型,而且-129不在缓存区里,所以应该是false。

-128在不在缓存区呢?把它和127,128一块测试,效果如下:

java 复制代码
false
true
true
false

从结果上看,说明128也并不在Integer的缓存区里。所以Integer的缓存范围是-128到127之间,并且包含两个边界值,一共256个数(别忘了有个0)。

下面对Integer的相关源码解析一下:

上面的代码Integer在创建对象时会使用到valueOf方法,下面来看一下这个方法:

java 复制代码
    /**
     * 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
     */
    @IntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

我们可以发现当i在满足IntegerCache.low和i <= IntegerCache.high的时候直接返回一个IntegerCache里缓存的数据,而不满足的条件则是直接new一个新的Integer。

下面查看一下IntegerCache的源码:

java 复制代码
    /**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * jdk.internal.misc.VM class.
     *
     * WARNING: The cache is archived with CDS and reloaded from the shared
     * archive at runtime. The archived cache (Integer[]) and Integer objects
     * reside in the closed archive heap regions. Care should be taken when
     * changing the implementation and the cache array should not be assigned
     * with new Integer object(s) after initialization.
     */

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        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 {
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(h, 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
            CDS.initializeFromArchive(IntegerCache.class);
            int size = (high - low) + 1;

            // Use the archived cache if it exists and is large enough
            if (archivedCache == null || size > archivedCache.length) {
                Integer[] c = new Integer[size];
                int j = low;
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                archivedCache = c;
            }
            cache = archivedCache;
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

可以看到low是-128,high虽然并没有在定义的时候赋值,但是执行静态代码块的时候把127赋值给了high,这就是缓存的数据范围。通过代码分析,可以看到**static final Integer[] cache;**保存了从-128到127的数据,所以我们创建Integer对象时如果在这个区间,其实使用的都是缓存对象,所以使用==判断是true,反之为false,这边使用的是设计模式中的享元模式。

相关推荐
maizeman126几秒前
R语言统计分析——ggplot2绘图4——刻面
开发语言·r语言·可视化·ggplot·刻面
for6212 分钟前
一文读懂fgc之cms
java·jvm·实践
DARLING Zero two♡26 分钟前
C++传送锚点的内存寻址:内存管理
开发语言·c++·内存管理
花心蝴蝶.34 分钟前
MyBatis 入门
java·spring boot·后端·mybatis
敖行客 Allthinker41 分钟前
从崩溃难题看 C 标准库与 Rust:线程安全问题引发的深度思考
开发语言·软件需求
Kerwin要坚持日更1 小时前
一文讲解Java中的BIO、NIO、AIO之间的区别
java·开发语言
earthzhang20212 小时前
《深入浅出HTTPS》读书笔记(31):HTTPS和TLS/SSL
开发语言·网络·python·https·1024程序员节
汤姆yu2 小时前
基于Springboot的社区药房管理系统
java·spring boot·后端·社区药房
程思扬2 小时前
Android笔记:android 动态设置backgroundTint
android·java·网络·笔记·android-studio
__如风__2 小时前
Nuitka打包python脚本
开发语言·python