字节码分析-控制流

源码

package java.bytecode;

/**
 * 控制流示例 - 演示if-else、switch、for循环、while循环、增强for循环
 */
public class ControlFlowExample {

    // if-else示例
    public void ifElseExample(int value) {
        if (value > 0) {
            System.out.println("Positive");
        } else if (value < 0) {
            System.out.println("Negative");
        } else {
            System.out.println("Zero");
        }
    }

    // switch示例
    public void switchExample(int value) {
        switch (value) {
            case 1:
                System.out.println("One");
                break;
            case 2:
                System.out.println("Two");
                break;
            default:
                System.out.println("Other");
        }
    }

    // for循环示例
    public void forLoopExample() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }

    // 增强for循环示例
    public void enhancedForLoopExample(String[] array) {
        for (String item : array) {
            System.out.println(item);
        }
    }

    // while循环示例
    public void whileLoopExample() {
        int i = 0;
        while (i < 10) {
            System.out.println(i);
            i++;
        }
    }
}

结构化反解析

Classfile /D:/zcp/github/yggdrasil/java/bytecode/ControlFlowExample.class
  Last modified 2025-12-3; size 1119 bytes
  MD5 checksum 838814412d6efb6ccb3fbd152537cd4e
  Compiled from "ControlFlowExample.java"
public class java.bytecode.ControlFlowExample
  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/lang/System.out:Ljava/io/PrintStream;
   #8 = Class              #10            // java/lang/System
   #9 = NameAndType        #11:#12        // out:Ljava/io/PrintStream;
  #10 = Utf8               java/lang/System
  #11 = Utf8               out
  #12 = Utf8               Ljava/io/PrintStream;
  #13 = String             #14            // Positive
  #14 = Utf8               Positive
  #15 = Methodref          #16.#17        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #16 = Class              #18            // java/io/PrintStream
  #17 = NameAndType        #19:#20        // println:(Ljava/lang/String;)V
  #18 = Utf8               java/io/PrintStream
  #19 = Utf8               println
  #20 = Utf8               (Ljava/lang/String;)V
  #21 = String             #22            // Negative
  #22 = Utf8               Negative
  #23 = String             #24            // Zero
  #24 = Utf8               Zero
  #25 = String             #26            // One
  #26 = Utf8               One
  #27 = String             #28            // Two
  #28 = Utf8               Two
  #29 = String             #30            // Other
  #30 = Utf8               Other
  #31 = Methodref          #16.#32        // java/io/PrintStream.println:(I)V
  #32 = NameAndType        #19:#33        // println:(I)V
  #33 = Utf8               (I)V
  #34 = Class              #35            // java/bytecode/ControlFlowExample
  #35 = Utf8               java/bytecode/ControlFlowExample
  #36 = Utf8               Code
  #37 = Utf8               LineNumberTable
  #38 = Utf8               ifElseExample
  #39 = Utf8               StackMapTable
  #40 = Utf8               switchExample
  #41 = Utf8               forLoopExample
  #42 = Utf8               enhancedForLoopExample
  #43 = Utf8               ([Ljava/lang/String;)V
  #44 = Class              #45            // "[Ljava/lang/String;"
  #45 = Utf8               [Ljava/lang/String;
  #46 = Utf8               whileLoopExample
  #47 = Utf8               SourceFile
  #48 = Utf8               ControlFlowExample.java
{
  public void ifElseExample(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: ifle          15
         4: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #13                 // String Positive
         9: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: goto          38
        15: iload_1
        16: ifge          30
        19: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        22: ldc           #21                 // String Negative
        24: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        27: goto          38
        30: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        33: ldc           #23                 // String Zero
        35: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        38: return
      LineNumberTable:
        line 10: 0
        line 11: 4
        line 12: 15
        line 13: 19
        line 15: 30
        line 17: 38

  public void switchExample(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: lookupswitch  { // 2
                       1: 28
                       2: 39
                 default: 50
            }
        28: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        31: ldc           #25                 // String One
        33: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        36: goto          58
        39: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        42: ldc           #27                 // String Two
        44: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        47: goto          58
        50: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        53: ldc           #29                 // String Other
        55: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        58: return
      LineNumberTable:
        line 21: 0
        line 23: 28
        line 24: 36
        line 26: 39
        line 27: 47
        line 29: 50
        line 31: 58

  public void forLoopExample();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush        10
         5: if_icmpge     21
         8: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: iload_1
        12: invokevirtual #31                 // Method java/io/PrintStream.println:(I)V
        15: iinc          1, 1
        18: goto          2
        21: return
      LineNumberTable:
        line 35: 0
        line 36: 8
        line 35: 15
        line 38: 21

  public void enhancedForLoopExample(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=6, args_size=2
         0: aload_1
         1: astore_2
         2: aload_2
         3: arraylength
         4: istore_3
         5: iconst_0
         6: istore        4
         8: iload         4
        10: iload_3
        11: if_icmpge     34
        14: aload_2
        15: iload         4
        17: aaload
        18: astore        5
        20: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        23: aload         5
        25: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        28: iinc          4, 1
        31: goto          8
        34: return
      LineNumberTable:
        line 42: 0
        line 43: 20
        line 42: 28
        line 45: 34

  public void whileLoopExample();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush        10
         5: if_icmpge     21
         8: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: iload_1
        12: invokevirtual #31                 // Method java/io/PrintStream.println:(I)V
        15: iinc          1, 1
        18: goto          2
        21: return
      LineNumberTable:
        line 49: 0
        line 50: 2
        line 51: 8
        line 52: 15
        line 54: 21
}
SourceFile: "ControlFlowExample.java"

详细说明

条件跳转指令

if-else结构

if-else语句被转换为条件跳转指令:

if (value > 0) {
    // 正数处理
} else if (value < 0) {
    // 负数处理
} else {
    // 零处理
}

字节码实现:

0: iload_1          // 加载value到栈
1: ifle          15  // 如果<=0,跳转到15
4: ...              // 正数处理
12: goto          38 // 跳转到结束
15: iload_1          // 重新加载value
16: ifge          30 // 如果>=0,跳转到30
19: ...              // 负数处理
27: goto          38 // 跳转到结束
30: ...              // 零处理
38: return

switch语句

switch语句使用lookupswitch或tableswitch指令:

1: lookupswitch  { // 2
           1: 28
           2: 39
     default: 50
}

for循环

for循环被转换为条件跳转结构:

for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

字节码实现:

0: iconst_0         // 初始化i=0
1: istore_1         // 存储i
2: iload_1          // 加载i
3: bipush        10 // 加载10
5: if_icmpge     21 // 如果i>=10,跳转到21(结束)
8: ...              // 循环体
15: iinc          1, 1  // i++
18: goto          2  // 跳转到条件判断
21: return

增强for循环

增强for循环被转换为传统的索引循环:

for (String item : array) {
    System.out.println(item);
}

字节码实现:

0: aload_1          // 加载数组
1: astore_2         // 存储到局部变量2
2: aload_2          // 加载数组
3: arraylength      // 获取数组长度
4: istore_3         // 存储长度
5: iconst_0         // 初始化索引i=0
6: istore        4  // 存储索引
8: iload         4  // 加载索引
10: iload_3         // 加载长度
11: if_icmpge     34 // 如果i>=length,跳转到34
14: aload_2         // 加载数组
15: iload         4  // 加载索引
17: aaload          // 获取array[i]
18: astore        5 // 存储到item
20: ...             // 循环体
28: iinc          4, 1  // i++
31: goto          8  // 跳转到条件判断
34: return

while循环

while循环与for循环的字节码结构类似,都是条件跳转:

while (i < 10) {
    System.out.println(i);
    i++;
}

字节码实现与for循环基本相同,只是初始化部分在循环外部。