学过Java的同学或多或少都听过自动装箱拆箱,下边通过代码和字节码文件加深下对自动拆箱装箱的理解.
作为和基本数据类型对应的类类型存在,方便涉及到对象的操作,比如泛型必须要求我们是对象数据类型.
自动拆箱装箱发生在代码编译期间.
通过例子来看下自动拆箱装箱是怎么做的:
public static void main(String[] args) { Long a = 100L; Long b = 100L; long c = 100L; Long d = new Long(100); Long e = 1000L; Long f = 1000L; System.out.println(a == b); System.out.println(a == c); System.out.println(a == d); System.out.println(c == d); System.out.println(e == f); }
下面先公布答案:
true
true
false
true
false
蒙 a==b为true; 为什么 e==f就是false? a和c是怎么比较的? a和d又是什么情况?
接下来我们通过字节码文件看看到底有什么奥秘:
public static void main(java.lang.String[]); Code: 0: ldc2_w #2 // long 100l 3: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long; 6: astore_1 7: ldc2_w #2 // long 100l 10: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long; 13: astore_2 14: ldc2_w #2 // long 100l 17: lstore_3 18: new #5 // class java/lang/Long 21: dup 22: ldc2_w #2 // long 100l 25: invokespecial #6 // Method java/lang/Long."<init>":(J)V 28: astore 5 30: ldc2_w #7 // long 1000l 33: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long; 36: astore 6 38: ldc2_w #7 // long 1000l 41: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long; 44: astore 7 46: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 49: aload_1 50: aload_2 51: if_acmpne 58 54: iconst_1 55: goto 59 58: iconst_0 59: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 62: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 65: aload_1 66: invokevirtual #11 // Method java/lang/Long.longValue:()J 69: lload_3 70: lcmp 71: ifne 78 74: iconst_1 75: goto 79 78: iconst_0 79: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 82: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 85: aload_1 86: aload 5 88: if_acmpne 95 91: iconst_1 92: goto 96 95: iconst_0 96: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 99: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 102: lload_3 103: aload 5 105: invokevirtual #11 // Method java/lang/Long.longValue:()J 108: lcmp 109: ifne 116 112: iconst_1 113: goto 117 116: iconst_0 117: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 120: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 123: aload 6 125: aload 7 127: if_acmpne 134 130: iconst_1 131: goto 135 134: iconst_0 135: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 138: return }
鬼画符?我们看下这些鬼到底什么意思.
3: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
意思是执行 Long 的valueof()方法 参数为基本类型 返回值为Long类型
看看Long的valueof方法
public static Long valueOf(long l) { final int offset = 128; if (l >= -128 && l <= 127) { // will cache return LongCache.cache[(int)l + offset]; } return new Long(l); }
如果传入的 基本类型在-128-127之内就,就从LongCache中取数据返回给我们 .看下LongCache干了啥
private static class LongCache { private LongCache(){} static final Long cache[] = new Long[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Long(i - 128); } }
原来如此, -128-127就直接返回给我们chche中的数据,超出这个范围直接new一个给我们 .a==b为true,e==f为false就说得通了.
65: aload_1 66: invokevirtual #11 // Method java/lang/Long.longValue:()J 69: lload_3 70: lcmp
拿出变量a, 执行Long.longValue()返回一个基本数据类型 ,在和c比较.看下longValue方法
/** * Returns the value of this {@code Long} as a * {@code long} value. */ public long longValue() { return value; }
这部就是两个基本数据类型比较吗.
85: aload_1 86: aload 5 88: if_acmpne 95
取出a和d直接比较内存地址是否一样.铁定不一样呀.
剩下的大家可以自己看下,有不明白的可以评论问.
自动拆箱装箱没有什么神秘的.字节码可以告诉我们很东西.如果某些概念理解不了,试着看看字节码文件.说不定会豁然开朗.
如果发现文章中有不妥之处,希望大家指出,共同进步.