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时测试结果
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时测试结果
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
最开始测试使用的JDK版本(程序输出):
1.8.0_202
两者存在不同,使用 Eclipse新版本需要注意咯!
而且,某些1.8版的函数,在 jre 这个里面 是没有的。
参考文档
1、Java之IntegerCache简单介绍
使用反射来修改 cache的值很有意思!
2、Java Integer的缓存策略
3、