字节码分析-方法

源码

package java.bytecode;

/**
 * 方法示例 - 演示构造方法、实例方法、静态方法、方法重载
 */
public class MethodExample {

    private int value;

    // 无参构造方法
    public MethodExample() {
        this.value = 0;
    }

    // 有参构造方法
    public MethodExample(int value) {
        this.value = value;
    }

    // 实例方法
    public void instanceMethod() {
        System.out.println("instanceMethod()");
    }

    // 方法重载 - int参数
    public void instanceMethod(int param) {
        System.out.println("instanceMethod(int): " + param);
    }

    // 方法重载 - String参数
    public void instanceMethod(String param) {
        System.out.println("instanceMethod(String): " + param);
    }

    // 静态方法
    public static void staticMethod() {
        System.out.println("MethodExample.staticMethod()");
    }

    // 返回类型的方法
    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

结构化反解析

Classfile /D:/zcp/github/yggdrasil/java/bytecode/MethodExample.class
  Last modified 2025-12-3; size 1139 bytes
  MD5 checksum 5f965d55b8debd0e3bcf120445787bc1
  Compiled from "MethodExample.java"
public class java.bytecode.MethodExample
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5.#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Fieldref           #8.#9          // java/bytecode/MethodExample.value:I
   #8 = Class              #10            // java/bytecode/MethodExample
   #9 = NameAndType        #11:#12        // value:I
  #10 = Utf8               java/bytecode/MethodExample
  #11 = Utf8               value
  #12 = Utf8               I
  #13 = Fieldref           #14.#15        // java/lang/System.out:Ljava/io/PrintStream;
  #14 = Class              #16            // java/lang/System
  #15 = NameAndType        #17:#18        // out:Ljava/io/PrintStream;
  #16 = Utf8               java/lang/System
  #17 = Utf8               out
  #18 = Utf8               Ljava/io/PrintStream;
  #19 = String             #20            // instanceMethod()
  #20 = Utf8               instanceMethod()
  #21 = Methodref          #22.#23        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #22 = Class              #24            // java/io/PrintStream
  #23 = NameAndType        #25:#26        // println:(Ljava/lang/String;)V
  #24 = Utf8               java/io/PrintStream
  #25 = Utf8               println
  #26 = Utf8               (Ljava/lang/String;)V
  #27 = Class              #28            // java/lang/StringBuilder
  #28 = Utf8               java/lang/StringBuilder
  #29 = Methodref          #27.#3         // java/lang/StringBuilder."<init>":()V
  #30 = String             #31            // instanceMethod(int):
  #31 = Utf8               instanceMethod(int):
  #32 = Methodref          #27.#33        // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #33 = NameAndType        #34:#35        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #34 = Utf8               append
  #35 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #36 = Methodref          #27.#37        // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  #37 = NameAndType        #34:#38        // append:(I)Ljava/lang/StringBuilder;
  #38 = Utf8               (I)Ljava/lang/StringBuilder;
  #39 = Methodref          #27.#40        // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #40 = NameAndType        #41:#42        // toString:()Ljava/lang/String;
  #41 = Utf8               toString
  #42 = Utf8               ()Ljava/lang/String;
  #43 = String             #44            // instanceMethod(String):
  #44 = Utf8               instanceMethod(String):
  #45 = String             #46            // MethodExample.staticMethod()
  #46 = Utf8               MethodExample.staticMethod()
  #47 = Utf8               Code
  #48 = Utf8               LineNumberTable
  #49 = Utf8               (I)V
  #50 = Utf8               instanceMethod
  #51 = Utf8               staticMethod
  #52 = Utf8               getValue
  #53 = Utf8               ()I
  #54 = Utf8               setValue
  #55 = Utf8               SourceFile
  #56 = Utf8               MethodExample.java
{
  private int value;
    descriptor: I
    flags: ACC_PRIVATE

  public java.bytecode.MethodExample();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_0
         6: putfield      #7                  // Field value:I
         9: return
      LineNumberTable:
        line 11: 0
        line 12: 4
        line 13: 9

  public java.bytecode.MethodExample(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iload_1
         6: putfield      #7                  // Field value:I
         9: return
      LineNumberTable:
        line 16: 0
        line 17: 4
        line 18: 9

  public void instanceMethod();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #19                 // String instanceMethod()
         5: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 22: 0
        line 23: 8

  public void instanceMethod(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: new           #27                 // class java/lang/StringBuilder
         6: dup
         7: invokespecial #29                 // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #30                 // String instanceMethod(int):
        12: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        15: iload_1
        16: invokevirtual #36                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        19: invokevirtual #39                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        25: return
      LineNumberTable:
        line 27: 0
        line 28: 25

  public void instanceMethod(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: new           #27                 // class java/lang/StringBuilder
         6: dup
         7: invokespecial #29                 // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #43                 // String instanceMethod(String):
        12: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        15: aload_1
        16: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: invokevirtual #39                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        25: return
      LineNumberTable:
        line 32: 0
        line 33: 25

  public static void staticMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #45                 // String MethodExample.staticMethod()
         5: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 37: 0
        line 38: 8

  public int getValue();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #7                  // Field value:I
         4: ireturn
      LineNumberTable:
        line 42: 0

  public void setValue(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #7                  // Field value:I
         5: return
      LineNumberTable:
        line 46: 0
        line 47: 5
}
SourceFile: "MethodExample.java"

详细说明

方法描述符

字节码中使用描述符来表示方法的参数和返回值:

方法调用指令

方法重载

方法重载通过不同的方法描述符来区分。例如:
- instanceMethod() - 描述符:()V
- instanceMethod(int) - 描述符:(I)V
- instanceMethod(String) - 描述符:(Ljava/lang/String;)V

编译器会根据参数类型生成不同的方法描述符,从而在字节码层面区分重载方法。

构造方法

构造方法在字节码中名为<init>,使用invokespecial指令调用父类构造方法:

public MethodExample();
  Code:
     0: aload_0
     1: invokespecial #1  // Method java/lang/Object."<init>":()V
     4: aload_0
     5: iconst_0
     6: putfield      #7  // Field value:I
     9: return

静态方法

静态方法使用ACC_STATIC标志,调用时使用invokestatic指令:

public static void staticMethod();
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
     0: getstatic     #13  // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #45  // String MethodExample.staticMethod()
     5: invokevirtual #21  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     8: return

字符串拼接优化

Java编译器会将字符串拼接(如"instanceMethod(int): " + param)优化为使用StringBuilder:

3: new           #27  // class java/lang/StringBuilder
6: dup
7: invokespecial #29  // Method java/lang/StringBuilder."<init>":()V
10: ldc           #30 // String instanceMethod(int):
12: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: iload_1
16: invokevirtual #36 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
19: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;