关于Integer类中Cache的解读

我们以几道常见的面试题开头

 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

原文地址:https://www.cnblogs.com/bianjunting/p/13922944.html