字节码分析-方法
源码
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"
详细说明
方法描述符
字节码中使用描述符来表示方法的参数和返回值:
()V- 无参,返回void(I)V- 一个int参数,返回void(Ljava/lang/String;)V- 一个String参数,返回void()I- 无参,返回int(I)V- 一个int参数,返回void
方法调用指令
invokevirtual- 调用实例方法(虚方法调用,支持多态)invokestatic- 调用静态方法invokespecial- 调用构造方法、私有方法或父类方法(如super()调用)invokeinterface- 调用接口方法
方法重载
方法重载通过不同的方法描述符来区分。例如:
- 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;