Java中Integer(缓存机制)分析
先上一段代码
public static void main(String[] args) {
Integer a = 1;
Integer b = 1;
System.out.println("a == b " +(a == b));
Integer c = 128;
Integer d = 128;
System.out.println("c == d " + (c == d));
}
//运行之后的输出结果是:
//a == b true
//c == d false
为什幺为产生这样的结果呢?
我们知道如果两个引用指向同一个对象,用 == 来判断就是相等的,而当指向不同对象即使他们内容相等最终结果也是不相等。
那这样看来,第一条输出语句也应该是false 。
哈哈这就是一个有趣的地方。
首先解释一下java的缓存机制:Integer缓存是 Java 5 中引入的一个有助于节省内存、提高性能的特性。
常量池
Integer中有个静态内部类IntegerCache,里面有个cache[],叫做静态常量池,常量池的大小为一个字节,这个静态常量池也就是(cache数组),他会在jvm初始化的时候,把从(-128,127)之间的数字提早缓存到了本地内存中,如果初始化是数字是(-128~127)之间的数字,会直接从内存中取出,不需要新建一个对象.
首先看一下JDK源码
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");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
// Load IntegerCache.archivedCache from archive, if possible
VM.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {
}
}
当创建Integer对象时:
例如:Integer a = 1;
调用的其实是Integer.valueOf(a)方法,(这是一个自动装箱的过程)代码为:
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之间,它就从缓存中返回实例。反之则 new 一个Integer对象
所以这也就是为什么第一条输出语句是true的原因,因为他们都指向提前缓存好的对象。
总结
Integer中存在缓存区,这个缓存会在Integer类第一次被使用的时候被初始化出来256个对象从(-128-127)所以当定义值的时候,会先在缓存区里面找,若找到则将该对象指向它,没有则在堆里面重新new一个对象.
那么如下结果就是不相等的
Integer e = 128;
Integer f = 128;
System.out.println(e == f);//false
上面就相当于:
Integer e = new Integer(128);
Integer f = new Integer(128);
System.out.printfln(e == f)//false
那么(e == f)肯定就是false
注意
Integer 在与 int类型的值在比较的时候 是用自身的value进行比较(拆箱的过程)
Integer e = 128;
int f = 128;
System.out.println(e == f); //true
拓展
Byte、Short、Integer、Long、Character都具有缓存机制。缓存工作都是在静态块中完成,在类生命周期的初始化阶段执行。
Byte,Short,Integer,Long为 -128 到 127
Character范围为 0 到 127
Double ,Float 没有。