深入理解jvm虚拟机第316页关于自动装箱的陷阱:
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
System.out.println(c == d); //true
System.out.println(e == f); // false
System.out.println(c == (a + b)); //true
System.out.println(c.equals(a + b));//true
System.out.println(g == (a + b));//true
System.out.println(g.equals(a + b));//false
简单一点说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
声明阶段使用自动装箱,将基本数据类型int自动转换为包装类型Integer,但是基本数据类型能表示的范围是-128~127之间。
1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址
2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
public com.yy.dto.TT();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(1)方法
4: astore_1 //将栈顶引用型数据存入局部变量
5: iconst_2
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(2)方法
9: astore_2
10: iconst_3
11: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(3)方法
14: astore_3
15: iconst_3
16: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(3)方法
19: astore 4
21: sipush 321 //将一个短整型常量推入栈顶
24: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
27: astore 5
29: sipush 321
32: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
35: astore 6
37: ldc2_w #3 // long 3l 将long或double型常量值从常量池中推送至栈顶(宽索引)
40: invokestatic #5 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;自动装箱,3L转换为Long类型
43: astore 7
45: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream; 输出流
48: aload_3
49: aload 4
51: if_acmpne 58 //比较栈顶两引用型数值,当结果不相等时跳转,这里比较c和d,即指向同一地址。
54: iconst_1
55: goto 59
58: iconst_0
59: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
62: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
65: aload 5
67: aload 6
69: if_acmpne 76 // 这里比较e和f,由于e和f是两个对象,地址不是同一个,所以为false
72: iconst_1
73: goto 77
76: iconst_0
77: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
80: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
83: aload_3
84: invokevirtual #8 // Method java/lang/Integer.intValue:()I 拆箱 c由Integer转为int的3
87: aload_1
88: invokevirtual #8 // Method java/lang/Integer.intValue:()I 把Integer1转为int 1
91: aload_2
92: invokevirtual #8 // Method java/lang/Integer.intValue:()I 把Integer2转为2
95: iadd // int型的1和2进行相加操作,基本数据类型使用==则比较数值,即3 = 1+2
96: if_icmpne 103
99: iconst_1
100: goto 104
103: iconst_0
104: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
107: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
110: aload_3
111: aload_1
112: invokevirtual #8 // Method java/lang/Integer.intValue:()I
115: aload_2
116: invokevirtual #8 // Method java/lang/Integer.intValue:()I
119: iadd
120: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
123: invokevirtual #9 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z 调用的Integer的equals方法,比较数值是否相等。看文末Integer的equals方法源码。
126: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
129: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
132: aload 7
134: invokevirtual #10 // Method java/lang/Long.longValue:()J将Long类型转换为long类型
137: aload_1
138: invokevirtual #8 // Method java/lang/Integer.intValue:()I
141: aload_2
142: invokevirtual #8 // Method java/lang/Integer.intValue:()I
145: iadd
146: i2l
147: lcmp
148: ifne 155
151: iconst_1
152: goto 156
155: iconst_0
156: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
159: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
162: aload 7
164: aload_1
165: invokevirtual #8 // Method java/lang/Integer.intValue:()I
168: aload_2
169: invokevirtual #8 // Method java/lang/Integer.intValue:()I
172: iadd
173: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
176: invokevirtual #11 // Method java/lang/Long.equals:(Ljava/lang/Object;)Z 调用Long类型的equals方法,由于a+b进行运算,需要自动拆箱,然后变为int型1和2求和得3,由于基本数据类型不能用于equals方法,自动装箱为Integer类型的3,而Long类型的equals方法,比较的若不是Long类型,直接返回false。
179: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
182: return
}
Integer的equals方法源码:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
该方法中将Integer类型的obj转换为int型,然后使用 == ,即比较两个基本数据类型的数值是否相等。
Long类型的equals的方法源码如下:
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}