要理解裝箱和拆箱的概念,就要理解Java數據類型
裝箱:把基本類型用它們相應的引用類型包裝起來,使其具有對象的性質。int包裝成Integer、float包裝成Float
拆箱:和裝箱相反,將引用類型的對象簡化成值類型的數據
Integer a = 100; 這是自動裝箱 (編譯器調用的是static Integer valueOf(int i))
int b = new Integer(100); 這是自動拆箱
看下面一段代碼
m1
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m11(); dt.m12(); } public void m11() { Integer a = new Integer(100); Integer b = 100; System.out.println("m11 result " + (a == b)); } public void m12() { Integer a = new Integer(128); Integer b = 128; System.out.println("m12 result " + (a == b)); } }
打印結果是什么?
m11 result false
m12 result false
“==”比較的是地址,而a和b兩個對象的地址不同,即是兩個對象,所以都是false
通過javap解析字節碼,內容如下
public void m11(); Code: 0: new #44; //class java/lang/Integer 3: dup 4: bipush 100 6: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 9: astore_1 10: bipush 100 12: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 15: astore_2 16: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 19: new #59; //class java/lang/StringBuilder 22: dup 23: ldc #61; //String m11 result 25: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 28: aload_1 29: aload_2 30: if_acmpne 37 33: iconst_1 34: goto 38 37: iconst_0 38: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 41: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 44: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 47: return public void m12(); Code: 0: new #44; //class java/lang/Integer 3: dup 4: sipush 128 7: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 10: astore_1 11: sipush 128 14: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 17: astore_2 18: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 21: new #59; //class java/lang/StringBuilder 24: dup 25: ldc #82; //String m12 result 27: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 30: aload_1 31: aload_2 32: if_acmpne 39 35: iconst_1 36: goto 40 39: iconst_0 40: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 43: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 46: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 49: return
m2
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m21(); dt.m22(); } public void m21() { Integer a = new Integer(100); Integer b = new Integer(100); System.out.println("m21 result " + (a == b)); } public void m22() { Integer a = new Integer(128); Integer b = new Integer(128); System.out.println("m22 result " + (a == b)); } }
打印結果是
m21 result false
m22 result false
a和b仍是兩個對象
javap解析內容
public void m21();
Code:
0: new #44; //class java/lang/Integer
3: dup
4: bipush 100
6: invokespecial #46; //Method java/lang/Integer."<init>":(I)V
9: astore_1
10: new #44; //class java/lang/Integer
13: dup
14: bipush 100
16: invokespecial #46; //Method java/lang/Integer."<init>":(I)V
19: astore_2
20: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream;
23: new #59; //class java/lang/StringBuilder
26: dup
27: ldc #84; //String m21 result
29: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
32: aload_1
33: aload_2
34: if_acmpne 41
37: iconst_1
38: goto 42
41: iconst_0
42: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
45: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
48: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
51: return
public void m22();
Code:
0: new #44; //class java/lang/Integer
3: dup
4: sipush 128
7: invokespecial #46; //Method java/lang/Integer."<init>":(I)V
10: astore_1
11: new #44; //class java/lang/Integer
14: dup
15: sipush 128
18: invokespecial #46; //Method java/lang/Integer."<init>":(I)V
21: astore_2
22: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream;
25: new #59; //class java/lang/StringBuilder
28: dup
29: ldc #86; //String m22 result
31: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
34: aload_1
35: aload_2
36: if_acmpne 43
39: iconst_1
40: goto 44
43: iconst_0
44: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
47: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
50: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
53: return
m3
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m31(); dt.m32(); } public void m31() { Integer a = 100; Integer b = 100; System.out.println("m31 result " + (a == b)); } public void m32() { Integer a = 128; Integer b = 128; System.out.println("m32 result " + (a == b)); } }
打印結果
m31 result true
m32 result false
為什么有第一個是true,第二個是false呢?觀察javap解析的數據
javap解析內容
public void m31();
Code:
0: bipush 100
2: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
5: astore_1
6: bipush 100
8: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
11: astore_2
12: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream;
15: new #59; //class java/lang/StringBuilder
18: dup
19: ldc #88; //String m31 result
21: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
24: aload_1
25: aload_2
26: if_acmpne 33
29: iconst_1
30: goto 34
33: iconst_0
34: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
37: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
40: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
43: return
public void m32();
Code:
0: sipush 128
3: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
6: astore_1
7: sipush 128
10: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
13: astore_2
14: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream;
17: new #59; //class java/lang/StringBuilder
20: dup
21: ldc #90; //String m32 result
23: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
26: aload_1
27: aload_2
28: if_acmpne 35
31: iconst_1
32: goto 36
35: iconst_0
36: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
39: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
42: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
45: return
m4
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m41(); dt.m42(); } public void m41() { Integer a = Integer.valueOf(100); Integer b = 100; System.out.println("m41 result " + (a == b)); } public void m42() { Integer a = Integer.valueOf(128); Integer b = 128; System.out.println("m42 result " + (a == b)); } }
打印結果
m41 result true
m42 result false
javap解析內容
public void m41();
Code:
0: bipush 100
2: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
5: astore_1
6: bipush 100
8: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
11: astore_2
12: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream;
15: new #59; //class java/lang/StringBuilder
18: dup
19: ldc #92; //String m41 result
21: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
24: aload_1
25: aload_2
26: if_acmpne 33
29: iconst_1
30: goto 34
33: iconst_0
34: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
37: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
40: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
43: return
public void m42();
Code:
0: sipush 128
3: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
6: astore_1
7: sipush 128
10: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
13: astore_2
14: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream;
17: new #59; //class java/lang/StringBuilder
20: dup
21: ldc #94; //String m42 result
23: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
26: aload_1
27: aload_2
28: if_acmpne 35
31: iconst_1
32: goto 36
35: iconst_0
36: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
39: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
42: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
45: return
}
分析
javap是Java自帶的一個工具,可以反編譯,也可以查看Java編譯器生成的字節碼(上面代碼只使用了javap -c DataType),是分析代碼的一個好工具,具體怎么使用請Google一下
先看一下m4,為什么運行結果中出現了“true”呢,true說明a、b是同一個對象。
但a對象是調用Integer.valueOf()生成的,b是通過自動裝箱生成的對象,為什么會是同一個對象呢?再看一下字節碼吧,畢竟Java程序是依靠虛擬機運行字節碼實現的。
m41這個方法只適用了一次valueOf(),但字節碼中出現了兩次,說明自動裝箱時也調用了valueOf()。
下面是valueOf()具體實現
/** * Returns a <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If a new <tt>Integer</tt> instance is not required, this method * should generally be used in preference to the constructor * {@link #Integer(int)}, as this method is likely to yield * significantly better space and time performance by caching * frequently requested values. * * @param i an <code>int</code> value. * @return a <tt>Integer</tt> instance representing <tt>i</tt>. * @since 1.5 */ public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); }
在【-128,127】之間的數字,valueOf返回的是緩存中的對象,所以兩次調用返回的是同一個對象。