欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java字节码例子解析

程序员文章站 2022-05-12 14:21:59
...

举个简单的例子:

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返回值.

Java字节码例子解析

 

 

然后执行如下指令:

$ 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 ]



}

参考自:http://www.importnew.com/13107.htm