Java 装箱与拆箱详解
前言:
要理解装箱和拆箱的概念,就要理解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
- </init></init></init></init>
-
复制代码
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
- * {[url=home.php?mod=space&uid=17823]@LINK[/url] #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返回的是缓存中的对象,所以两次调用返回的是同一个对象。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持! |