• Java之Integer$IntegerCache初探(AutoBoxCacheMax)


    JDK 8

    ---

    int是Java的基本数据类型,而Integer是其包装器类。

    在创建Integer时,如果使用构造函数,则会在 堆中新建对象,而使用 valueOf的话,则 可能 会从其 内部类 IntegerCache 的 静态常量 cache 中获取数据。

    “可能”是指 JDK默认情况下,cache中保存的数据是 -128~127,共计 256个Integer对象。

    Integer部分源码:

        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
        
        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");
            
            }
            high = h;
            
            // ...
        }

    IntegerCache会初始化一个Integer数组——cache,最小值 -128,最大值 默认为 127,但可以从属性 java.lang.Integer.IntegerCache.high 中获取——从而修改最大值。

    修改 java.lang.Integer.IntegerCache.high 的方式,在运行程序的时候添加下面的VM参数:

    -XX:AutoBoxCacheMax=1024

    注:1024是我自己设置的值。修改后,cache数组的范围就扩大了,但是,不能小于127——代码控制了的

    测试代码:

    	/**
    	 * 测试 == 和 equals
    	 * @author ben
    	 * @date 2021-08-05 11:35:08 CST
    	 */
    	public static void testEquals() {
    		cs.accept("testEquals...start");
    		Integer i1 = 1;
    		Integer i2 = new Integer(1);
    		Integer i3 = new Integer("1");
    		Integer i4 = Integer.valueOf(1);
    		Integer i5 = Integer.valueOf("1");
    		
    		cs.accept("i1=" + i1);
    		cs.accept("i2=" + i2);
    		cs.accept("i3=" + i3);
    		cs.accept("i4=" + i4);
    		cs.accept("i5=" + i5);
    
    		cs.accept("hashCode");
    		cs.accept("i1 hashCode=" + i1.hashCode());
    		cs.accept("i2 hashCode=" + i2.hashCode());
    		cs.accept("i3 hashCode=" + i3.hashCode());
    		cs.accept("i4 hashCode=" + i4.hashCode());
    		cs.accept("i5 hashCode=" + i5.hashCode());
    
    		cs.accept("identityHashCode");
    		cs.accept("i1 identityHashCode=" + System.identityHashCode(i1));
    		cs.accept("i2 identityHashCode=" + System.identityHashCode(i2));
    		cs.accept("i3 identityHashCode=" + System.identityHashCode(i3));
    		cs.accept("i4 identityHashCode=" + System.identityHashCode(i4));
    		cs.accept("i5 identityHashCode=" + System.identityHashCode(i5));
    
    		cs.accept("==:");
    		cs.accept(i1 == i2);
    		cs.accept(i1 == i3);
    		cs.accept(i1 == i4);
    		cs.accept(i1 == i5);
    		cs.accept("equals:");
    		cs.accept(i1.equals(i2));
    		cs.accept(i1.equals(i3));
    		cs.accept(i1.equals(i4));
    		cs.accept(i1.equals(i5));
    		
    		cs.accept("");
    		
    		i1 = 999;
    		i2 = new Integer(999);
    		i3 = new Integer("999");
    		i4 = Integer.valueOf(999);
    		i5 = Integer.valueOf("999");
    		
    		cs.accept("i1=" + i1);
    		cs.accept("i2=" + i2);
    		cs.accept("i3=" + i3);
    		cs.accept("i4=" + i4);
    		cs.accept("i5=" + i5);
    
    		cs.accept("hashCode:");
    		cs.accept("i1 hashCode=" + i1.hashCode());
    		cs.accept("i2 hashCode=" + i2.hashCode());
    		cs.accept("i3 hashCode=" + i3.hashCode());
    		cs.accept("i4 hashCode=" + i4.hashCode());
    		cs.accept("i5 hashCode=" + i5.hashCode());
    
    		cs.accept("identityHashCode:");
    		cs.accept("i1 identityHashCode=" + System.identityHashCode(i1));
    		cs.accept("i2 identityHashCode=" + System.identityHashCode(i2));
    		cs.accept("i3 identityHashCode=" + System.identityHashCode(i3));
    		cs.accept("i4 identityHashCode=" + System.identityHashCode(i4));
    		cs.accept("i5 identityHashCode=" + System.identityHashCode(i5));
    
    		cs.accept("==:");
    		cs.accept(i1 == i2);
    		cs.accept(i1 == i3);
    		cs.accept(i1 == i4);
    		cs.accept(i1 == i5);
    		cs.accept("equals:");
    		cs.accept(i1.equals(i2));
    		cs.accept(i1.equals(i3));
    		cs.accept(i1.equals(i4));
    		cs.accept(i1.equals(i5));
    		cs.accept("testEquals...end.");
    		
    		String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    		System.out.println("integerCacheHighPropValue=" + integerCacheHighPropValue);
    	}

    注:== 除了比较值是否相同,还会比较对象的地址——对于类对象来说;equals 只是比较值。

    1、未修改时测试结果

    测试-默认
    testEquals...start
    i1=1
    i2=1
    i3=1
    i4=1
    i5=1
    hashCode
    i1 hashCode=1
    i2 hashCode=1
    i3 hashCode=1
    i4 hashCode=1
    i5 hashCode=1
    identityHashCode
    i1 identityHashCode=135721597
    i2 identityHashCode=142257191
    i3 identityHashCode=1044036744
    i4 identityHashCode=135721597
    i5 identityHashCode=135721597
    ==:
    false
    false
    true
    true
    equals:
    true
    true
    true
    true
    
    i1=999
    i2=999
    i3=999
    i4=999
    i5=999
    hashCode:
    i1 hashCode=999
    i2 hashCode=999
    i3 hashCode=999
    i4 hashCode=999
    i5 hashCode=999
    identityHashCode:
    i1 identityHashCode=1826771953
    i2 identityHashCode=1406718218
    i3 identityHashCode=245257410
    i4 identityHashCode=1705736037
    i5 identityHashCode=455659002
    ==:
    false
    false
    false
    false
    equals:
    true
    true
    true
    true
    testEquals...end.
    integerCacheHighPropValue=null
    

    2、修改为1024时测试结果

    测试1024
    testEquals...start
    i1=1
    i2=1
    i3=1
    i4=1
    i5=1
    hashCode
    i1 hashCode=1
    i2 hashCode=1
    i3 hashCode=1
    i4 hashCode=1
    i5 hashCode=1
    identityHashCode
    i1 identityHashCode=135721597
    i2 identityHashCode=142257191
    i3 identityHashCode=1044036744
    i4 identityHashCode=135721597
    i5 identityHashCode=135721597
    ==:
    false
    false
    true
    true
    equals:
    true
    true
    true
    true
    
    i1=999
    i2=999
    i3=999
    i4=999
    i5=999
    hashCode:
    i1 hashCode=999
    i2 hashCode=999
    i3 hashCode=999
    i4 hashCode=999
    i5 hashCode=999
    identityHashCode:
    i1 identityHashCode=1826771953
    i2 identityHashCode=1406718218
    i3 identityHashCode=245257410
    i4 identityHashCode=1826771953
    i5 identityHashCode=1826771953
    ==:
    false
    false
    true
    true
    equals:
    true
    true
    true
    true
    testEquals...end.
    integerCacheHighPropValue=1024
    

    3、修改为0时测试结果

    测试0
    testEquals...start
    i1=1
    i2=1
    i3=1
    i4=1
    i5=1
    hashCode
    i1 hashCode=1
    i2 hashCode=1
    i3 hashCode=1
    i4 hashCode=1
    i5 hashCode=1
    identityHashCode
    i1 identityHashCode=135721597
    i2 identityHashCode=142257191
    i3 identityHashCode=1044036744
    i4 identityHashCode=135721597
    i5 identityHashCode=135721597
    ==:
    false
    false
    true
    true
    equals:
    true
    true
    true
    true
    
    i1=999
    i2=999
    i3=999
    i4=999
    i5=999
    hashCode:
    i1 hashCode=999
    i2 hashCode=999
    i3 hashCode=999
    i4 hashCode=999
    i5 hashCode=999
    identityHashCode:
    i1 identityHashCode=1826771953
    i2 identityHashCode=1406718218
    i3 identityHashCode=245257410
    i4 identityHashCode=1705736037
    i5 identityHashCode=455659002
    ==:
    false
    false
    false
    false
    equals:
    true
    true
    true
    true
    testEquals...end.
    integerCacheHighPropValue=0
    

    结果分析:

    1、3的结果相同,因为不能设置为小于 127的值;

    2设置为1024后,999也会存在于缓存了;

    所有使用 new Integer() 的 都是 对内存对象,和cache中的 使用 == 时,返回false。

    另外检查了 Character、Byte、Short、Long,都有cache机制,但是,都是固定的 -128~127,不能通过配置更改。

        // Long的代码,其它几种 整形 类似
        private static class LongCache {
            private LongCache(){}
    
            static final Long cache[] = new Long[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Long(i - 128);
            }
        }

    上面测试的JDK版本:Java HotSpot

    >java -version
    java version "1.8.0_202"
    Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
    Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

    我使用的IDE是Eclipse,版本 Version: 2021-03 (4.19.0),其默认提供了JRE来运行Java程序,支持 到了 Java 15:

    在使用这个jre来运行程序会怎样呢?

    出错了:sun.misc.VM.getSavedProperty 没法使用

    并且Integer的两个 构造函数被标记为 @Deprecated(since="9"),用valueOf就好了。

        @Deprecated(since="9")
        public Integer(int value) {
            this.value = value;
        }

    IntegerCache获取 cache的最大值的方式:

        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");
    

    可是,在测试程序里面执行 VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 时 出现了异常

    Exception in thread "main" java.lang.IllegalAccessError: class aug.Test80201 (in unnamed module @0x3caeaf62) 
    cannot access class jdk.internal.misc.VM (in module java.base) because module java.base does not export 
    jdk.internal.misc to unnamed module @0x3caeaf62
    	at aug.Test80201.testEquals(Test80201.java:167)
    	at aug.Test80201.main(Test80201.java:35)

    不过,测试前面的配置——-XX:AutoBoxCacheMax=1024,仍然是有效的。

    这个jre的版本是多少呢?

    Runtime.version()
    15.0.2+7-27
    System.getProperty("java.version")
    15.0.2

    前面的异常,应该和 Java 9 开始使用的 模块系统有关系,还需了解。

    最开始测试使用的JDK版本(程序输出):

    1.8.0_202

    两者存在不同,使用 Eclipse新版本需要注意咯

    而且,某些1.8版的函数,在 jre 这个里面 是没有的。

    参考文档

    1、Java之IntegerCache简单介绍

    使用反射来修改 cache的值很有意思!

    2、Java Integer的缓存策略

    3、Java 9 新特性

    其中的 模块系统

    4、

  • 相关阅读:
    [TJOI2013]循环格
    [CQOI2017]小Q的表格
    【51nod 1514】 美妙的序列
    【bzoj3456】 城市规划
    [SHOI2010]最小生成树
    CF438E The Child and Binary Tree
    bzoj 4712: 洪水
    POJ-3069 Saruman's Army---区间选点
    POJ-3617 Best Cow Line---字符串贪心
    HDU-1850 Being a Good Boy in Spring Festival---尼姆博奕的运用
  • 原文地址:https://www.cnblogs.com/luo630/p/15104936.html
Copyright © 2020-2023  润新知