Integer缓存策略
在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。
下面代码展示Integer的缓存功能(Integer自动装箱):
public class IntertorTest { //Integer自动装箱(Integer a = 2;--会变成Integer a = Integer.valueOf(2);) public static void main(String[] args) { Integer a = 2; Integer b = 2; // a=b:true System.out.println("a==b:" + (a==b)); // a.equals(b):true System.out.println("a.equals(b):" + a.equals(b)); Integer c = 200; Integer d = 200; // c==d:false System.out.println("c==d:" + (c==d)); // c.equals(d):true System.out.println("c.equals(d):" + c.equals(d)); /** * Java 中,== 比较的是对象引用,而 equals 比较的是值。 */ } }
public class IntertorTest { //使用Integer构造器创建对象。 public static void main(String[] args) { Integer a = new Integer(2); Integer b = new Integer(2); // a=b:false System.out.println("a==b:" + (a==b)); // a.equals(b):true System.out.println("a.equals(b):" + a.equals(b)); } }
上面的规则适用于整数区间 -128 到 +127。这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。
IntegerCache---Integer的缓存类
IntegerCache是Integer类中一个私有的静态类。我们先看下源代码。
/** * 缓存以支持自动装箱的对象身份语义 * 根据JLS(java语音规范)要求,-128和127(含)。 * * 缓存在初次使用时初始化。 * 缓存的大小可以通过{-XX:AutoBoxCacheMax = <size>}选项进行控制最大值。 * 在VM初始化期间,java.lang.Integer.IntegerCache.high属性 * 可以设置并保存在私有系统属性中 * sun.misc.VM类。 */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // 高值可能由属性配置 int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // 最大数组大小为Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); //范围[-128,127]必须实施(JLS7 5.1.7) assert Integer.IntegerCache.high >= 127; }
缓存通过一个for循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache的整数数组中。这个缓存会在Integer类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。
JSL(java语言规范如下):
如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。
这种缓存行为不仅适用于Integer对象,也适用于其他其他所有的基本类型的包装类型。
我们针对所有整数类型的类都有类似的缓存机制。
有ByteCache用于缓存Byte对象
有ShortCache用于缓存Short对象
有LongCache用于缓存Long对象
有CharacterCache用于缓存Character对象
Byte,Short,Long 有固定范围: -128 到 127。对于Character,范围是 0 到 127。除了 Integer 可以通过JVM参数改变范围外,其它的都不行。