我们先看一个关于Integer的例子

public static void main(String[] args) {
// TeODO Auto-generated method stu
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0); System.out.println("i1=i2\t" + (i1 == i2));
System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));
System.out.println("i4=i5\t" + (i4 == i5));
System.out.println("i4=i5+i6\t" + (i4 == i5 + i6)); System.out.println();
}
}

结果:

i1=i2     true
i1=i2+i3  true
i4=i5  false
i4=i5+i6  true

再看一个例子

public static void main(String[] args) {
// TeODO Auto-generated method stu
Integer i1 = 400;
Integer i2 = 400;
Integer i3 = 0;
Integer i4 = new Integer(400);
Integer i5 = new Integer(400);
Integer i6 = new Integer(0); System.out.println("i1=i2\t" + (i1 == i2));
System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));
System.out.println("i4=i5\t" + (i4 == i5));
System.out.println("i4=i5+i6\t" + (i4 == i5 + i6)); System.out.println();
}
}

结果

i1=i2     false
i1=i2+i3  true
i4=i5  false
i4=i5+i6  true

比较上面两个例子,我们发现:两个例子代码几乎一样,就是值不一样,40和400的区别怎么会造成如此大的结果差别呢??

我们用上篇博客的方法,用javap看他们的反编译结果

public class com.study.main.Test extends java.lang.Object{
public com.study.main.Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return public static void main(java.lang.String[]);
Code:
0: sipush 400 //40时我们用cipush(下同) cipush(char 类型)的值范围是-128——127,sipush(short 类型)的值范围是2^15——2^15-1,
3: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int
eger;
6: astore_1
7: sipush 400
10: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int
eger;
13: astore_2
14: iconst_0
15: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int
eger;
18: astore_3
19: new #3; //class java/lang/Integer
22: dup
23: sipush 400
26: invokespecial #4; //Method java/lang/Integer."<init>":(I)V
29: astore 4
31: new #3; //class java/lang/Integer
34: dup
35: sipush 400
38: invokespecial #4; //Method java/lang/Integer."<init>":(I)V
41: astore 5
43: new #3; //class java/lang/Integer
46: dup
47: iconst_0
48: invokespecial #4; //Method java/lang/Integer."<init>":(I)V
51: astore 6
53: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
56: new #6; //class java/lang/StringBuilder
59: dup
60: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V
63: ldc #8; //String i1=i2\t
65: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
68: aload_1
69: aload_2
70: if_acmpne 77
73: iconst_1
74: goto 78
77: iconst_0
78: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
81: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
84: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
87: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
90: new #6; //class java/lang/StringBuilder
93: dup
94: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V
97: ldc #13; //String i1=i2+i3\t
99: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
102: aload_1
103: invokevirtual #14; //Method java/lang/Integer.intValue:()I
106: aload_2
107: invokevirtual #14; //Method java/lang/Integer.intValue:()I
110: aload_3
111: invokevirtual #14; //Method java/lang/Integer.intValue:()I
114: iadd
115: if_icmpne 122
118: iconst_1
119: goto 123
122: iconst_0
123: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
126: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
129: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
132: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
135: new #6; //class java/lang/StringBuilder
138: dup
139: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V
142: ldc #15; //String i4=i5\t
144: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
147: aload 4
149: aload 5
151: if_acmpne 158
154: iconst_1
155: goto 159
158: iconst_0
159: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
162: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
165: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
168: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
171: new #6; //class java/lang/StringBuilder
174: dup
175: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V
178: ldc #16; //String i4=i5+i6\t
180: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
183: aload 4
185: invokevirtual #14; //Method java/lang/Integer.intValue:()I
188: aload 5
190: invokevirtual #14; //Method java/lang/Integer.intValue:()I
193: aload 6
195: invokevirtual #14; //Method java/lang/Integer.intValue:()I
198: iadd
199: if_icmpne 206
202: iconst_1
203: goto 207
206: iconst_0
207: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
210: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
213: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
216: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
219: invokevirtual #17; //Method java/io/PrintStream.println:()V
222: return }

比较后我们惊人的发现,两者其实没有什么区别

只有这里:

0:   sipush  400 //40时我们用cipush(下同)  cipush(char 类型)的值范围是-128——127,sipush(short 类型)的值范围是2^15——2^15-1

我们看到第12行: 3:   invokestatic    #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int

在Integer中是调用Integer.valueOf初始化对象的

Integer.valueOf函数

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

IntegerCache

  private static class IntegerCache {
static final int high;
static final Integer cache[]; static {
final int low = -128; // high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is 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() {}
}

通过研究发现:Integer.valueOf()中有个内部类IntegerCache(类似于一个常量数组,也叫对象池),它维护了一个Integer数组cache,长度为(128+127+1)=256;Integer类中还有一个Static Block(静态块),如上所示。

从这个静态块可以看出,Integer已经默认创建了数值【-128-127】的Integer缓存数据。所以使用Integer i1=40时,JVM会直接在该在对象池找到该值的引用。

也就是说这种方式声明一个Integer对象时,JVM首先会在Integer对象的缓存池中查找有木有值为40的对象,如果有直接返回该对象的引用;如果没有,则使用New keyword创建一个对象,并返回该对象的引用地址。因为Java中【==】比较的是两个对象是否是同一个引用(即比较内存地址),i2和i2都是引用的同一个对象,So i1==i2结果为”true“;而使用new方式创建的i4=new Integer(40)、i5=new Integer(40),虽然他们的值相等,但是每次都会重新Create新的Integer对象,不会被放入到对象池中,所以他们不是同一个引用,输出false。

  对于i1==i2+i3、i4==i5+i6结果为True,是因为,Java的数学计算是在内存栈里操作的,Java会对i5、i6进行拆箱操作,其实比较的是基本类型(40=40+0),他们的值相同,因此结果为True。

但是但为400时,这个时候已经超过了cache的范围,所以都得重新初始化对象

05-11 16:56
查看更多