Java Integer 缓存特性(Integer最大/小值探究整型的自动装箱)

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Integer 缓存特性(Integer最大/小值探究整型的自动装箱)相关的知识,希望对你有一定的参考价值。

文章目录

问题引出

Integer最大/小值

java中Integer是有最大值和最小值的
最大值为

Integer.MAX_VALUE = 2147483647

最小值为

Integer.MIN_VALUE = -2147483648

注意:两个值并没有互为相反数

 Integer.MAX_VALUE + 1 = Integer.MIN_VALUE

同理

Integer.MIN_VALUE - 1 = Integer.MAX_VALUE

Integer最大/小值案例

但是用到了这样的一个案例:

public static void test() 
    //true
    Integer a1 = 127, b1 = 127;
    System.out.println(a1 == b1);
    //false
    Integer a2 = new Integer(127);
    Integer b2 = new Integer(127);
    System.out.println(a2 == b2);
    //false
    Integer a3 = 128, b3 = 128;
    System.out.println(a3 == b3);
    //true
    Integer a4 = 128, b4 = 128;
    System.out.println(a4.equals(b4));


public static void main(String[] args) 
    test();

比较答案:

true
false
false
true

结果原因

  • 第一个使用"=="判断 Integer a1 = 127 和 Integer b1 = 127
    相等原因:Integer的取值范围是-128~127

  • 第二个使用"=="判断Integer a2 = new Integer(127) 和 Integer b2 = new Integer(127)
    不相等原因:装箱时,java为了提高效率,IntegerCache类中有一个数组将-128<=i<=127范围之内的数据打包成缓存里的Integer对象了,因此不用new,这个区间里的值用直接=赋值方法得到的变量地址就是同一个,而超出这个范围的数值就会new一个Integer对象出来

  • 第三个使用"=="判断Integer a3=128 和 Integer b3 = 128
    不相等原因:因为Integer类型赋值范围在-128—127之间,超出这个范围的数值就会重新new一个Integer对象出来,直接用==去比较是比较a3和b3的地址,a3和b3的地址是不相等的

  • 第四个使用使用"=="equals()方法判断Integer a4=128 和 Integerb4 = 128
    相等原因:使用equals()方法比较的是a4和b4的数值

注意点:"=="可以用于原始值进行比较,也可以用于对象进行比较,当用于对象与对象之间比较时,比较的不是对象代表的值,而是检查两个对象是否是同一对象,这个比较过程中没有自动装箱发生。进行对象值比较不应该使用”==“,而应该使用对象对应的equals方法。

小总结

JVM会自动维护八种基本类型的常量池,int常量池中初始化-128~127的范围,所以当为Integer i=127时,在自动装箱过程中是取自常量池中的数值,而当Integer i=128时,128不在常量池范围内,所以在自动装箱过程中需new 128,所以地址不一样。

上面就用到了Java自动装箱的概念,下面我们来深入了解一下:

Integer 自动装箱

IntegerCache缓存

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

Integer中有个静态内部类IntegerCache,里面有个cache[],也就是Integer常量池,常量池的大小为一个字节(-128~127)。JDK源码如下(摘自JDK1.8源码):

    /**
    * 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 -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
    * sun.misc.VM class.
    */
    private static class IntegerCache 
        static final int low = -128;
        static final int high;
        static final Integer cache[];
     
        static 
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) 
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low));
            
            high = h;
     
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        
     
        private IntegerCache() 
    

当创建Integer对象时,不使用new Integer(int i)语句,大小在-128~127之间,对象存放在Integer常量池中。

例如:Integer a = 10;

调用的是Integer.valueOf()方法,代码为:

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

这也是自动装箱的代码实现。

Java自动装箱

JAVA将基本类型自动转换为包装类的过程称为自动装箱(autoboxing)。

实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在Java 6 后,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。(通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改)

缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。

测试情况:

int i = 10;
int i1 = 10;
Integer in1 = 10;
Integer in2 = 10;
Integer in3 = new Integer(10);
Integer in4 = new Integer(10);
Integer in5 = 199;
Integer in6 = 199;

System.out.println(i == i1);		// true
System.out.println(i == in1);		// true
System.out.println(i == in2);		// true
System.out.println(i == in3);		// true

System.out.println(in1 == in2);		// true
System.out.println(in5 == in6);		// false

System.out.println(in1 == in3);		// false

System.out.println(in3 == in4);		// false

在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:
如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。

所有整数类型的类都有类似的缓存机制:

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

Byte,Short,Long 的缓存池范围默认都是: -128 到 127。可以看出,Byte的所有值都在缓存区中,用它生成的相同值对象都是相等的。

所有整型(Byte,Short,Long)的比较规律与Integer是一样的。

同时Character 对象也有CharacterCache 缓存 池,范围是 0 到 127。

除了 Integer 可以通过参数改变范围外,其它的都不行。

创作打卡挑战赛 赢取流量/现金/CSDN周边激励大奖

以上是关于Java Integer 缓存特性(Integer最大/小值探究整型的自动装箱)的主要内容,如果未能解决你的问题,请参考以下文章

转理解Java Integer的缓存策略

理解Java Integer的缓存策略

理解Java Integer的缓存策略

Integer 如何实现节约内存和提升性能的?

java基础---Integer缓存机制---Integer缓存机制

翻译Integer Cache In Java(在Java中的Integer缓存机制)