我们以几道常见的面试题开头
1 import org.junit.Test; 2 3 public class Demo { 4 private int num = 1; 5 6 @Test 7 public void test() { 8 Integer x = 5; 9 int y = 5; 10 System.out.println(x == y); // true 11 12 Integer i1 = 100; 13 Integer i2 = 100; 14 System.out.println(i1 == i2); // true 15 16 Integer i3 = 128; 17 Integer i4 = 128; 18 System.out.println(i3 == i4); // false 19 } 20 }
上面的代码中已经标明题目的答案,今天我将从字节码的角度解读为什么答案是那样的
对于第一段代码
1 Integer x = 5; 2 int y = 5; 3 System.out.println(x == y);
这是这段代码所对应的字节码
0 iconst_5 1 invokestatic #3 <java/lang/Integer.valueOf> 4 astore_1 5 iconst_5 6 istore_2 7 getstatic #4 <java/lang/System.out> 10 aload_1 11 invokevirtual #5 <java/lang/Integer.intValue> 14 iload_2 15 if_icmpne 22 (+7) 18 iconst_1 19 goto 23 (+4) 22 iconst_0 23 invokevirtual #6 <java/io/PrintStream.println> 26 return
可以看出,在字节码的第一行,调用了Integer的静态方法valueOf(int),valueOf方法的目的是减少内存的负担,具体实现方法是,Integer类内部有一个Integer类型的cache数组用来存储[-128, 127]内的整数的Integer对象的引用,所以每当int类型自动装箱的时候,会调用Integer的valueOf方法,如果该数字在缓存范围内则直接返回该对象的引用,否则调用Integer的构造方法,创建一个新的对象
在字节码第11行将 x 自动拆箱,然后与y进行比较
对于第二段代码
1 Integer i1 = 100; 2 Integer i2 = 100; 3 System.out.println(i1 == i2);
其对应的字节码
26 bipush 100 28 invokestatic #3 <java/lang/Integer.valueOf> 31 astore_3 32 bipush 100 34 invokestatic #3 <java/lang/Integer.valueOf> 37 astore 4 39 getstatic #4 <java/lang/System.out> 42 aload_3 43 aload 4 45 if_acmpne 52 (+7) 48 iconst_1 49 goto 53 (+4) 52 iconst_0 53 invokevirtual #6 <java/io/PrintStream.println>
可以看到字节码第28行和第34行,分别调用了Integer的静态方法valueOf,由于他们是相同对象的引用,因此在valueOf中返回的是同一个对象的引用,因此使用==判断地址后得到的是相同的值
第三段代码同理,由于128不属于Integer的Cache范围,因此调用两次valueOf方法意味着生成了两个不同的对象,也就是说答案是false