IntegerCache

今天发现一个很好玩的东西,我们先看看代码

public class IntegerCacheTest {
	
	public static void main(String[] args) {
		Integer a = 100 , b = 100;
		System.out.println(a == b); // true

		Integer c = 129 , d = 129;
		System.out.println(c == d); // false ?
		System.out.println(c.equals(d)); // true
	
	}
}

突然脑袋上飞出了好多的问号。

这是为嘛呢?因为 IntegerCache,看下面的代码

/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */ 
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");
      if (integerCacheHighPropValue != null) {
        try {
          int i = parseInt(integerCacheHighPropValue);
          i = Math.max(i, 127);
          // Maximum array size is 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++);

      // range [-128, 127] must be interned (JLS7 5.1.7)
      assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

在看一下

public static Integer valueOf(int i) {
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
  return new Integer(i);
}

通过源码我们看到如果在 -128 ~ 127 之间都是直接从缓存中读取值,所以在此范围内的相同的值内存地址是一样的,但超过这个范围就会创建一个新的 Integer ,导致两个相同的值并不在一个内存地址。这也是为什么超过这个区间使用 “==” 来判断两个值是否相等的时候是 “false” 了。

还可以通过 -XX:AutoBoxCacheMax=size 来设置最大边界。

然后我们在看一下为什么用 equals 时候两个超过边界的值也会相等,来上源码

public boolean equals(Object obj) {
  if (obj instanceof Integer) {
    return value == ((Integer)obj).intValue();
  }
  return false;
}

这段代码可以看出使用 equals 进行比较的时候是比较两个 Integer 的值。所以在比较的时候还是使用 equals 更加准确。