📚《深入浅出JVM字节码》

《Java虚拟机字节码:从入门到实战》的开源版本。作者通过自己的实战经验,整合出一套适合新手的高效学习教程。归纳并提炼知识点,制定合理路线,帮助读者更快掌握核心技术。


访问静态字段与静态方法

与非静态方法的调用和非静态字段的访问不同,获取静态字段、修改静态字段、调用静态方法不需要一个该类型的对象引用作为隐式参数,且静态方法的局部变量表不会存储this引用。

静态字段的初始赋值由编译器编译后在类初始化方法中生成赋值的字节码指令,而被声明为final的静态字段初始赋值则在类加载的准备阶段赋值。

读写静态字段的字节码指令是getstatic与putstatic,这两条指令都要求一个操作数,操作数的值为常量池中某个CONSTANT_Fieldref_info常量的索引。getstatic指令的操作码为0xB2,putstatic指令的操作码为0xB3。

读写静态字段的案例代码如下。

public class StaticFieldMain {
    static String name;

    public static void main(String[] args) {
        name = "wujiuye";
        System.out.println(name);
    }
}

使用javap命令输出这段代码的字节码如下。

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    Code:
       0: ldc           #2                  // String wujiuye
       2: putstatic     #3                  // Field name:Ljava/lang/String;
       5: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       8: getstatic     #3                  // Field name:Ljava/lang/String;
      11: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: return

偏移量为0和2的字节码指令完成为静态字段name赋值,先使用ldc字节码指令将putstatic指令所需要的参数放入操作数栈顶,putstatic指令将栈顶的元素赋值给类的静态字段。

调用静态方法的案例代码如下。

public class StaticMethodMain {
    static void show(String msg){
        System.out.println(msg);
    }
    public static void main(String[] args) {
        StaticMethodMain.show("hello word!");
    }
}

例子中,在main方法调用show静态方法,调用show方法需要传递一个参数,在show方法中打印main方法传递的参数。对应的字节码如下。

static void show(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokevirtual #3                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       7: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    Code:
       0: ldc           #4                  // String hello word!
       2: invokestatic  #5                  // Method show:(Ljava/lang/String;)V
       5: return

main方法中,偏移量为0和2的字节码指令完成调用show方法,ldc指令将调用show方法所需的参数放入操作数栈的栈顶。方法需要多少个参数就将多少个参数放入操作数栈顶,如果传null则使用aconst_null指令,aconst_null指令的操作码为0x01。调用静态方法的指令是invokestatic,指令的操作码为0xB8,该指令需要一个操作数,操作数的值必须是常量池中某个CONSTANT_Methodref_info常量的索引。在show方法中,偏移量为3的aload_0指令获取到的局部变量不再是this,而是方法的第一个参数。


发布于:2021 年 08 月 21 日
作者: 吴就业
链接: https://github.com/wujiuye/JVMByteCodeGitBook
来源: Github Pages 开源电子书《深入浅出JVM字节码》(《Java虚拟机字节码从入门到实战》的第二版),未经作者许可,禁止转载!


📚目录