现象描述
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(引用相同,从缓存中取)Integer c = 200;
Integer d = 200;
System.out.println(c == b); // false(超出缓存范围,new Integer(200))
原因分析
Integer从Java 5开始,引入了缓存机制,用于缓存一定范围内的Integer对象。
- 默认缓存范围是-128~127
- 这些值对应的Integer对象在JVM启动时就被创建,并缓存在内存中
Integer缓存与JVM的关系
Integer中有一个静态内部类
private static class IntegerCache {static final int high;static final Integer cache[];static {final int low = -128;// high value may be configured by propertyint h = 127;if (integerCacheHighPropValue != null) {// Use Long.decode here to avoid invoking methods that// require Integer's autoboxing cache to be initializedint i = Long.decode(integerCacheHighPropValue).intValue();i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = 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() {}}
从JVM初始化的配置中获取integerCacheHighPropValue
,如果大于127,那么初始化的最大值就是integerCacheHighPropValue
cache数组的个数是hight-low+1
在cache中初始化从low到high的数字
public static Integer valueOf(int i) {if(i >= -128 && i <= IntegerCache.high)return IntegerCache.cache[i + 128];elsereturn new Integer(i);}
当调用Integer.valueOf
的时候,如果i的范围在-127~IntegerCache.high
,就直接从缓存中取。因为是从缓存中直接获取的,所以即使多次获取,对象的内存地址是相同的。
但是如果i不在这个范围内,那么回返回一个新的对象,这时即使i的数字相同,但多个对象的内存地址不同。用==
来比较,结果会是false
.
编码
Integer a = 200;
Integer b = 200;
int c = 200;// ❌ 危险:结果依赖缓存
System.out.println(a == b); // false// ✅ 安全:比较值
System.out.println(a.equals(b)); // true// ✅ 安全高效
System.out.println(a == c); // true(拆箱比较)// ✅ 最安全(推荐)
System.out.println(Objects.equals(a, b)); // true
Integer
VSInteger
:必须用equals()
或Object.equals
- Integer VS int:用
==
更安全、更高效 - 为了避免null的问题,有限使用
Objects.equals(a,b)