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

posted @ 2019-07-05 14:36  西伯利亚虎  阅读(412)  评论(0编辑  收藏  举报

Permanence, perseverance and persistence in spite of all obstacles, discouragements and impossibilities: It is this, that in all things distinguishes the strong soul from the weak.