完全理解 java操作数栈和局部变量表

概要

近期学习到字节码操控框架ASM,其中对方法的定义需要设置最大操作数栈和局部变量表。
于是,自己又复习了一遍java栈帧的概念。

如果对栈帧概念还不了解的读者推荐看下此文章:详细解析Java虚拟机的栈帧结构

例子综述

本文将会通过诸多字节码的例子,来具体分析在不同情况下的方法的操作数栈和局部变量表。

本文的分析主要基于javac和javap的使用:

  1. 首先用javac生成java文件编译后的class文件
  2. 再使用"javap -v xxx.class"来输出该class文件的信息
操作数栈可以复用

首先要强调个概念:“操作数栈可以复用”。如下两个例子中test方法的操作数栈都会是2。

public class Test {
  public int test(int a, int b) {
    int c = a + b;
    return c;
  }
}
public class Test {
  public int test(int a, int b) {
    int c = a + b;
    c = a + b;
    c = a + b;
    c = a + b;
    return c;
  }
}

1、对象方法:方法参数

  • 操作数栈:2
    先load a,再load b
  • 局部变量表:3
    this,a,b
public class Test {
  public int test(int a, int b) {
    return a + b;
  }
}
public int test(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: ireturn
      LineNumberTable:
        line 10: 0

2、对象方法:本地变量+方法参数

  • 操作数栈:2
    先load a,再load b
  • 局部变量表:2
    this,b
public class Test {
  private int a = 0;
  public int test(int b) {
    return a + b;
  }
}
  public int test(int);
    descriptor: (I)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: getfield      #2                  // Field a:I
         4: iload_1
         5: iadd
         6: ireturn
      LineNumberTable:
        line 11: 0

3、对象方法:方法变量+方法参数

  • 操作数栈:2
    先load a,再load b
  • 局部变量表:4
    this,a,b,c
public class Test {
  public int test(int a, int b) {
    int c = a + b;
    return a + b;
  }
}
  public int test(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: istore_3
         4: iload_1
         5: iload_2
         6: iadd
         7: ireturn
      LineNumberTable:
        line 10: 0
        line 11: 4

4、静态方法:方法参数

  • 操作数栈:2
    先load a,再load b
  • 局部变量表:2
    a,b
public class Test {
  public static int test(int a, int b) {
    return a + b;
  }
}
  public static int test(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_0
         1: iload_1
         2: iadd
         3: ireturn
      LineNumberTable:
        line 10: 0

5、静态方法调用静态方法

  • 操作数栈:1
    将string“123” 压入栈中
  • 局部变量表:0
public class Test {
  public static int test() {
    add("123");
    return 0;
  }

  public static int add(String s) {
  }
}
  public static int test();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #2                  // String 123
         2: invokestatic  #3                  // Method add:(Ljava/lang/String;)V
         5: iconst_0
         6: ireturn
      LineNumberTable:
        line 10: 0
        line 11: 5

6、静态方法调用对象方法

  • 操作数栈:2
    将Test对象压入栈中,将string“123” 压入栈中
  • 局部变量表:0
public class Test {
  public static int test() {
    new Test().add("123");
    return 0;
  }

  public void add(String s) {
  }
}
  public static int test();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #2                  // class Test
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: ldc           #4                  // String 123
         9: invokevirtual #5                  // Method add:(Ljava/lang/String;)V
        12: iconst_0
        13: ireturn
      LineNumberTable:
        line 10: 0
        line 11: 12
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值