Integer缓存源码剖析
首先先看一个例题,思考一下下面这段程序会出现什么样的结果,由这道题我们对部分源码进行分析:
Integer a = 100; Integer b = 100; Integer c = 130; Integer d = 130; Integer e = new Integer(100); Integer f = new Integer(100); System.out.println(a==b); System.out.println(c==d); System.out.println(e==f);
看完上面的代码,自己的心里面是不是有了自己的答案,最终的答案是(点击+展开查看答案):
true false false
我们都知道Integer是int的封装类,通常对于基本数据类型直接赋值给封装类就是自动装箱,这样就会为Integer对象分配对内存,对象呢指向不同的地址,Java中==是比较的对象的地址,因此对于c==d为false我们都很确定,其他两对是什么情况呢???
1 private static class IntegerCache { 2 static final int low = -128; 3 static final int high; 4 static final Integer cache[]; 5 6 static { 7 int h = 127; 8 String integerCacheHighPropValue = 9 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 10 if (integerCacheHighPropValue != null) { 11 try { 12 int i = parseInt(integerCacheHighPropValue); 13 i = Math.max(i, 127); 14 // Maximum array size is Integer.MAX_VALUE 15 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 16 } catch( NumberFormatException nfe) { 17 // If the property cannot be parsed into an int, ignore it. 18 } 19 } 20 high = h; 21 22 cache = new Integer[(high - low) + 1]; 23 int j = low; 24 for(int k = 0; k < cache.length; k++) 25 cache[k] = new Integer(j++); 26 27 // range [-128, 127] must be interned (JLS7 5.1.7) 28 assert IntegerCache.high >= 127; 29 } 30 31 private IntegerCache() {} 32 }
IntegerCache是Integer的静态内部类,该类有一个Integer类型的缓存数组,显示默认会缓存[-128,127]之间的数字,默认实例化256个对象(25行),在-128到127之间呢必须被interned(27行),这些是都是静态并且final的,避免重复的实例化和回收,这样做的目的就是为了节省更大的空间,当一个Integer的值在缓存数组之间时,JVM就会直接把该对象在对象池的地址赋值给引用,因此a==b为true就很清楚了。另外,我们还可以在启动JVM时通过更改java.lang.Integer.IntegerCache.high的值来修改缓存的最大值,如果我们把该值修改为了300,那么缓存数组的范围就是[-128,300]
另外对于显式的创建Integer对象,JVM会直接分配新的空间,不会去对象池中检查是否有该对象,对于e==f为false也就很正常了。
下面演示更改缓存的最大值为300:
首先在run as ——>run Configurations ——>arguments——>VM arguments下配置
-Djava.lang.Integer.IntegerCache.high=300
点击apply,点击run
上面的例题的结果就变为了:
true true false