美文网首页
Java基础——包装类缓存

Java基础——包装类缓存

作者: zhangyaqi | 来源:发表于2020-08-04 13:01 被阅读0次

在开始之前,我们先来看一下Java语言规范(JLS7-5.1.7)中的一小段内容:

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

大致意思:

对boolean类型的值、byte类型的值、\u0000到\u007f(含)范围内的值、以及-128到127(含)范围内的int或者short类型的值进行自动装箱操作时,需要保证对字面量p进行任意两次装箱操作得到的对象r1和2都满足r1==r2。

结合上边的Java语言规范,我们来猜测一下下面代码的执行结果


    Integer num = 127;
    Integer num2 = 127;
    System.out.println(num == num2);
    System.out.println(num.equals(num2));

    Integer num5 = new Integer(127);
    System.out.println(num == num5);
    System.out.println(num.equals(num5));

    Integer num3 = 128;
    Integer num4 = 128;

    System.out.println(num3 == num4);
    System.out.println(num3.equals(num4));

这段代码的执行结果如下:


    true
    true
    false
    true
    false
    true

问题来了,为什么表示同样数字的Integer对象,在使用“==”和equals进行判断时,得出的结果确实如此的多变?其实这主要是因为Java的自动装箱和包装类缓存的共同作用引起的。自动装箱在的文章已经做了说明这里不再赘述,不清楚的朋友可以移步(这里)。

什么是包装类缓存呢 🤔?


还记得文章开头引用的一部分Java语言规范吗,包装类缓存就是为了实现这部分的语言规范而设计的。除了Float和Double外,其他的包装类内部都实现了针对其表示的基本类型的缓存机制,我们这里以Integer包装类的缓存为例来进行分析。下面我来一起看下自动装箱时调用的Integer.valueOf(int) 方法:


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

从上面的源码中我们可以看出,当定义的整数在一定范围内时,不论在什么地方定义,实际上返回的都是IntegerCache中初始化好的同一个对象。只有在整数值超出这个数组范围或者直接调用构造函数时,才会生成新的Integer对象。那么这个缓存的数值范围到底有多大呢,我一起来看一下。

首先我们来看一下IntegerCache的源代码:


    static final int low = -128;
    static final int high;
    static final Integer[] cache;
    static Integer[] archivedCache;

    static {
        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
                // 数组的大小上限为Integer.MAX_VALUE,缓存数值的最大值为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
        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 = c;
        }
        cache = archivedCache;
                // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

通过代码中for循环的部分可以看出,IntegerCache的缓存范围时通过参数low和high来控制的。而参数low定义为静态常量且值为-128,也就是说缓存的下限是无法修改;参数high则取127和java.lang.Integer.IntegerCache.high两者中的较大值(最大不能超过2147483518),想要自定义java.lang.Integer.IntegerCache.high的话,可以通过JVM启动参数-XX:AutoBoxCacheMax=来设置。

总结


  • Java的包装类默认缓存了true、false、-128~127、
  • 包装类对象之间进行相等判断时,要使用equals方法,决不能使用“==”
  • 可以通过JVM启动参数-XX:AutoBoxCacheMax=<size>来设置整数的缓存上限

相关文章

  • Java基础——包装类缓存

    在开始之前,我们先来看一下Java语言规范(JLS7-5.1.7)中的一小段内容: If the value p ...

  • 优秀博客集锦(一)

    理解Java Integer的缓存策略Java中Integer和其他包装类具有缓存机制,会缓存常用的一部分数字。 ...

  • [Java基础]包装类型

    [Java基础]包装类 了解一下 什么是包装类型在 Java 中, 数据类型总共可以分为2大类 : 基础数据类型和...

  • JDK 源码解析 —— Integer

    说到Java中的Integer包装类,大家或多或少的都听说过Integer缓存,下面我们先从Integer缓存相关...

  • Java基础-包装类

    为了让基本类型的数据进行更多的操作,java就为每种基本类型提供了对应的包装类类型 byte -------...

  • Java编程基础(11)

    Java编程基础知识:Java内置包装内 1.Java Object类详解:Object类的常用方法(equals...

  • java Integer包装类之自动装拆箱 + Integer

    java Integer包装类之自装拆箱 + Integer == (缓存池)面试题 Integer 自动装拆箱 ...

  • Java 基础 31 包装类

    1.1 基本类型包装类的概述   需求:我要判断一个数据是否在int范围内?要想判断一个数据是否在int范围内,首...

  • Java基础 (3) 包装类

    思考原生与包装类型的区别。装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。...

  • 一起学JDK源码 -- Float类

    前面几篇文章我们看了JAVA基本数据类型整型的包装类,接下来我们看下浮点型float的包装类Float类。 基础知...

网友评论

      本文标题:Java基础——包装类缓存

      本文链接:https://www.haomeiwen.com/subject/hhslrktx.html