Java5 为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。上面的规则默认适用于整数区间 -128 到 +127(这个整数区间可以通过启动应用的虚拟机参数修改:-XX:AutoBoxCacheMax)。这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
首先看代码:
public class TestInteger {
public static void main(String[] args) {
int i = 128;
Integer i2 = 128;
Integer i3 = new Integer(128);
//Integer 会自动拆箱为 int,所以为 true
System.out.println(i == i2);
System.out.println(i == i3);
System.out.println(“**************”);
Integer i5 = 127;//java 在编译的时候, 被翻译成 -> Integer i5 = Integer.valueOf(127);
Integer i6 = 127;
System.out.println(i5 == i6);//true
Integer i9 = 128;
Integer i10 = 128;
System.out.println(i9 == i10);//false
Integer ii5 = new Integer(127);
System.out.println(i5 == ii5); //false
Integer i7 = new Integer(128);
Integer i8 = new Integer(123);
System.out.println(i7 == i8); //false
}
}
首先,7 行和 8 行输出结果都为 true, 因为 Integer 和 int 比都会自动拆箱(jdk1.5 以上)。12 行的结果为 true, 而 15 行则为 false。java 在编译 Integer i5 = 127 的时候, 被翻译成 -> Integer i5 = Integer.valueOf(127); 所以关键就是看 valueOf() 函数了。只要看看 valueOf() 函数的源码就会明白了。JDK 源码的 valueOf 函数式这样的:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
看一下源码大家都会明白,对于 -128 到 127 之间的数,会进行缓存,Integer i5 = 127 时,会将 127 进行缓存,下次再写 Integer i6 = 127 时,就会直接从缓存中取,就不会 new 了。所以 12 行的结果为 true, 而 15 行为 false。对于 17 行和 20 行,因为对象不一样,所以为 false。对于以上的情况总结如下:
无论如何,Integer 与 new Integer 不会相等。不会经历拆箱过程,i3 的引用指向堆,而 i4 指向专门存放他的内存(常量池),他们的内存地址不一样,所以为 false
两个都是非 new 出来的 Integer,如果数在 -128 到 127 之间,则是 true, 否则为 false。java 在编译 Integer i2 = 128 的时候, 被翻译成 -> Integer i2 = Integer.valueOf(128); 而 valueOf() 函数会对 -128 到 127 之间的数进行缓存
两个都是 new 出来的, 都为 false
int 和 Integer(无论 new 否) 比,都为 true,因为会把 Integer 自动拆箱为 int 再去比
AutoBoxCacheMax 参数
// IntegerCache,Integer 类的内部类,注意它的属性都是定义为 static final
private static class IntegerCache {
// 缓存的下界,-128,不可变
static final int low = -128;
// 缓存上界,暂为 null
static final int high;
// 缓存的整型数组
static final Integer cache[];
static {
// 缓存上界,可以通过 JVM 参数来配置
int h = 127;
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”);
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// 最大的数组值是 Integer.MAX_VALUE
h = 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() {
}
}
-XX:AutoBoxCacheMax 这个参数是设置 Integer 缓存上限的参数, 在 VM 初始化期间 java.lang.Integer.IntegerCache.high 属性可以被设置和保存在私有的系统属性 sun.misc.VM class 中。理论上讲,当系统需要频繁使用 Integer 时,或者说堆内存中存在大量的 Integer 对象时,可以考虑提高 Integer 缓存上限,避免 JVM 重复创造对象,提高内存的使用率,减少 GC 的频率,从而提高系统的性能。理论归理论,这个参数能否提高系统系统关键还是要看堆中 Integer 对象到底有多少、以及 Integer 的创建的方式。如果堆中的 Integer 对象很少,重新设置这个参数并不会提高系统的性能。即使堆中存在大量的 Integer 对象,也要看 Integer 对象时如何产生的。
大部分 Integer 对象通过 Integer.valueOf() 产生。说明代码里存在大量的拆箱与装箱操作。这时候设置这个参数会系统性能有所提高。
大部分 Integer 对象通过反射,new 产生。这时候 Integer 对象的产生大部分不会走 valueOf() 方法,所以设置这个参数也是无济于事。
JDK 中其他类似的缓存
Integer 的缓存上限可以通过 Java 虚拟机参数修改,Byte、Short、Long、Character 的缓存则没法修改。
Byte
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i – 128));
}
}
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
Short
private static class ShortCache {
private ShortCache(){}
static final Short cache[] = new Short[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i – 128));
}
}
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) {// must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
Long
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i – 128);
}
}
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) {// will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
Character
private static class CharacterCache {
private CharacterCache(){}
static final Character cache[] = new Character[127 + 1];
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
public static Character valueOf(char c) {
if (c <= 127) {// must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
示例:
public class AllCacheDemo {
/**
* 演示 JDK 内部缓存
*/
public static void main(String[] args) {
Integer a = 28;
Integer b = 28;
println(a == b);
Byte c = 25;
Byte d = 25;
println(c==d);
Short p=12;
Short q=12;
println(p==q);
Long x=127L;
Long y=127L;
println(x==y);
Character m=’M’;
Character n=’M’;
println(m==n);
}
public static void println(Object o){
System.out.println(o);
}
}
作者:刘晓;花名:愚谷。点击 阅读更多 查看更多详情