public class Bytecode { public static void main(String arg[]){ Bytecode bc= new Bytecode(); System.out.println(bc.fib(4)); } public int fib(int N) { if (N <= 1) { return N; } return fib(N-1) + fib(N-2); } }
用一个递归程序深入理解字节码文件
public class Java_jvm.Bytecode minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #7.#19 // java/lang/Object."<init>":()V #2 = Class #20 // Java_jvm/Bytecode #3 = Methodref #2.#19 // Java_jvm/Bytecode."<init>":()V #4 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream; #5 = Methodref #2.#23 // Java_jvm/Bytecode.fib:(I)I #6 = Methodref #24.#25 // java/io/PrintStream.println:(I)V #7 = Class #26 // java/lang/Object #8 = Utf8 <init> #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 main #13 = Utf8 ([Ljava/lang/String;)V #14 = Utf8 fib #15 = Utf8 (I)I #16 = Utf8 StackMapTable #17 = Utf8 SourceFile #18 = Utf8 Bytecode.java #19 = NameAndType #8:#9 // "<init>":()V #20 = Utf8 Java_jvm/Bytecode #21 = Class #27 // java/lang/System #22 = NameAndType #28:#29 // out:Ljava/io/PrintStream; #23 = NameAndType #14:#15 // fib:(I)I #24 = Class #30 // java/io/PrintStream #25 = NameAndType #31:#32 // println:(I)V #26 = Utf8 java/lang/Object #27 = Utf8 java/lang/System #28 = Utf8 out #29 = Utf8 Ljava/io/PrintStream; #30 = Utf8 java/io/PrintStream #31 = Utf8 println #32 = Utf8 (I)V { public Java_jvm.Bytecode(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=2, args_size=1 0: new #2 // class Java_jvm/Bytecode 3: dup
然后因为invokespecial会消耗掉操作数栈顶的引用作为传给构造器的“this”参数,所以如果我们希望在invokespecial调用后在操作数栈顶还维持有一个指向新建对象的引用, 就得在invokespecial之前先“复制”一份引用
4: invokespecial #3 // Method "<init>":()V 7: astore_1 8: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 11: aload_1 12: iconst_4 13: invokevirtual #5 // Method fib:(I)I 16: invokevirtual #6 // Method java/io/PrintStream.println:(I)V 19: return LineNumberTable: line 5: 0 line 6: 8 line 7: 19 public int fib(int); descriptor: (I)I flags: ACC_PUBLIC Code: stack=4, locals=2, args_size=2 0: iload_1 1: iconst_1 2: if_icmpgt 7 5: iload_1 6: ireturn 7: aload_0 8: iload_1 9: iconst_1 10: isub 11: invokevirtual #5 // Method fib:(I)I 14: aload_0 15: iload_1 16: iconst_2 17: isub 18: invokevirtual #5 // Method fib:(I)I 21: iadd 22: ireturn LineNumberTable: line 9: 0 line 10: 5 line 12: 7 StackMapTable: number_of_entries = 1 frame_type = 7 /* same */ }