Java字节码例子解析
举个简单的例子:
public class Hello { public static void main(String[] args) { String string1 = "ab"; String string2 = "c"; String string3 = string1 + "c"; System.out.println(string1 == string3); } }
过程大致分析如图:
第一步 将线程栈中的string1、string2引用分别指向了常量池ab、c的地址。
第二步 轮到了string3 = string1 + "c",首先会初始化StringBuilder到堆中,然后调append将string1字符串拼接、然后调append再拼接"c"。
第三步 StringBuilder指向常量池的"abc"地址,然后通过toString返回值.
然后执行如下指令:
$ javac Hello.java //编译 $ javap -verbose Hello //反编译,结果如下:
Classfile /C:/Users/lisam/Desktop/新建文件夹/Hello.class Last modified 2018-9-17; size 706 bytes MD5 checksum 4d2164bd48f0690cad84271e27b237a5 Compiled from "Hello.java" public class Hello SourceFile: "Hello.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER //方法常量池 Constant pool: #1 = Methodref #11.#24 // java/lang/Object."<init>":()V #2 = String #25 // ab #3 = String #26 // c #4 = Class #27 // java/lang/StringBuilder #5 = Methodref #4.#24 // java/lang/StringBuilder."<init>":()V #6 = Methodref #4.#28 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #7 = Methodref #4.#29 // java/lang/StringBuilder.toString:()Ljava/lang/String; #8 = Fieldref #30.#31 // java/lang/System.out:Ljava/io/PrintStream; #9 = Methodref #32.#33 // java/io/PrintStream.println:(Z)V #10 = Class #34 // Hello #11 = Class #35 // java/lang/Object #12 = Utf8 <init> #13 = Utf8 ()V #14 = Utf8 Code #15 = Utf8 LineNumberTable #16 = Utf8 main #17 = Utf8 ([Ljava/lang/String;)V #18 = Utf8 StackMapTable #19 = Class #36 // "[Ljava/lang/String;" #20 = Class #37 // java/lang/String #21 = Class #38 // java/io/PrintStream #22 = Utf8 SourceFile #23 = Utf8 Hello.java #24 = NameAndType #12:#13 // "<init>":()V #25 = Utf8 ab #26 = Utf8 c #27 = Utf8 java/lang/StringBuilder #28 = NameAndType #39:#40 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #29 = NameAndType #41:#42 // toString:()Ljava/lang/String; #30 = Class #43 // java/lang/System #31 = NameAndType #44:#45 // out:Ljava/io/PrintStream; #32 = Class #38 // java/io/PrintStream #33 = NameAndType #46:#47 // println:(Z)V #34 = Utf8 Hello #35 = Utf8 java/lang/Object #36 = Utf8 [Ljava/lang/String; #37 = Utf8 java/lang/String #38 = Utf8 java/io/PrintStream #39 = Utf8 append #40 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #41 = Utf8 toString #42 = Utf8 ()Ljava/lang/String; #43 = Utf8 java/lang/System #44 = Utf8 out #45 = Utf8 Ljava/io/PrintStream; #46 = Utf8 println #47 = Utf8 (Z)V { public Hello(); 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 1: 0 public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=4, args_size=1 //将字符串"ab"压入常量池 0: ldc #2 // String ab //存储到局部变量表 2: astore_1 //将字符串"c"压入常量池 3: ldc #3 // String c //存储到局部变量表 5: astore_2 //String3的拼接过程中,会先new 6: new #4 // class java/lang/StringBuilder 9: dup //然后invokespecial调用初始化StringBuilder构造器 10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V //把局部变量表中n=1的引用(即步骤2: astore_1)的值"ab"装在到操作数栈中。 13: aload_1 //然后invokevirtual来调用方法append string1 14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; //将字符串"c"压入常量池 17: ldc #3 // String c //然后append "c" 19: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; //调用toString返回值 22: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; //然后将string3的值"abc"存储到局部变量表 25: astore_3 //获取类的静态域,这里拿到了静态System.out,并将值压入栈顶 26: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; //把局部变量表中n=1的引用(即步骤2: astore_1)的值"ab"装在到操作数栈中。 29: aload_1 //把局部变量表中n=3的引用(即步骤25: astore_3)的值"abc"装在到操作数栈中。 30: aload_3 //比较上面栈顶两引用型数值,当结果不相等时跳转 31: if_acmpne 38 //将int为1压入栈顶 34: iconst_1 35: goto 39 38: iconst_0 //调用静态类中System.out.println 39: invokevirtual #9 // Method java/io/PrintStream.println:(Z)V //返回空 42: return LineNumberTable: line 3: 0 line 4: 3 line 5: 6 line 6: 26 line 7: 42 StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 38 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream, int ] }
原文链接:Java字节码例子解析 - Lisam Blog - CSDN博客 https://blog.csdn.net/qq_28666081/article/details/82749655
参考链接:一文让你明白Java字节码 - 简书 https://www.jianshu.com/p/252f381a6bc4