JDK:1.8
/**
* 用于测试基本数据类型的自动拆箱和自动装箱
*/
public class AutoBox {
/**
* 测试整型的自动拆箱和缓冲
*/
static class TestInt{
public static void main(String[] args){
Integer integer = new Integer(100);
Integer integer1 = 100;
Integer integer2 = 100;
System.out.println(integer == integer1);//false
System.out.println(integer1 == integer2);//true
System.out.println(integer == integer2);//false
}
/*
这个是上面主函数的字节码,现在来分析为什么输出是如此:
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Integer
3: dup
4: bipush 100
6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V
//使用new在堆里面实例化一个integer对象
9: astore_1
10: bipush 100
12: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
//以100为参数调用integer类的静态方法
15: astore_2
16: bipush 100
18: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
//以100为参数调用integer类的静态方法
21: astore_3
22: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
25: aload_1
26: aload_2
27: if_acmpne 34
30: iconst_1
31: goto 35
34: iconst_0
35: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
38: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
41: aload_2
42: aload_3
43: if_acmpne 50
46: iconst_1
47: goto 51
50: iconst_0
51: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
54: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
57: aload_1
58: aload_3
59: if_acmpne 66
62: iconst_1
63: goto 67
66: iconst_0
67: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
70: return
在我们使用自动装箱来进行实例化integer对象时,第12、18行都是调用的integer类的静态方法valueOf,也就是说,导致
integer1与integer2指向同一个对象,而与integer指向不同对象的原因就是在这里,现在分析valueOf源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
从上面的源码看出来在传入的值处于某个区间时,返回的是同一个对象,只有在超出这个范围时才是在堆里面创建一个新的对象
也就是说integer1与integer2地址相同是因为100处于这个区间里面,现在继续分析IntegerCache的源码一探究竟,源码如下:
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:告诉我们这个可以配置?在类文档里面找到可以使用-XX:AutoBoxCacheMax=<size>配置
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);//high - low + 1 = Integer.MAX_VALUE;->high = Integer.MAX_VALUE - (-low) -1
} catch( NumberFormatException nfe) {}
}
high = h;
//这个就是被缓存的整型对象数组
cache = new Integer[(high - low) + 1];
int j = low;
//在这里进行了实例化,所以只要是配置范围里面的对象都已经被事先创建出来了。
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
}
综合上面的分析,如果我们使用自动装箱的方式,相当于隐式调用了valueOf函数,而这个函数会先判断该数值是否已经在配置
的缓存里面,如果在就直接返回,如果不在才创建新的对象,所以这就是上面输出的解释了。
剩下的基本数据类型包装的缓存如下:
Boolean:没有,一个正负要撒子缓存嘛。
Byte:缓存-128-127,恐怖,全部被缓存了,每一个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));
}
}
Character:缓存0-127
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);
}
}
Short: 缓存-128-127
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));
}
}
Float:没有!
Double:没有!
Long:缓存-128-127
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);
}
}
总结:只有int的范围可以配置,以后再有人问你int类型自动拆箱和装箱的过程,先问他-XX:AutoBoxCacheMax=<size>参数配置
的是啥,哈哈哈哈。(size大于127才有效,否则都是默认的127)
*/
}
}