0
点赞
收藏
分享

微信扫一扫

通过字节码指令, 分析JVM中代码的执行顺序

颜路在路上 2021-09-29 阅读 66
随笔

概述

下面代码执行的结果name的结果是多少? 在工作中遇到过类似的问题引发的bug, 故记录一下排查的过程

code

public class Comp {
    private String mark = ",";

    public Comp(String mark) {
        this.mark = mark;
    }

    private String name = "xx_oo".split(mark)[0];

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

类似的还有下面这一种

int[] arr = new int[]{1,2,3};
int index = 1;
arr[index++] = arr[index-1]+10 ;

字节码

public com.cache.demo.Comp(java.lang.String);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #2                  // String ,
       7: putfield      #3                  // Field mark:Ljava/lang/String;
      10: aload_0
      11: ldc           #4                  // String xx_oo
      13: aload_0
      14: getfield      #3                  // Field mark:Ljava/lang/String;
      17: invokevirtual #5                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
      20: iconst_0
      21: aaload
      22: putfield      #6                  // Field name:Ljava/lang/String;
      25: aload_0
      26: aload_1
      27: putfield      #3                  // Field mark:Ljava/lang/String;
      30: return

从字节码指令来看, 该对象的实例化顺序:
空参数实例化(invokespecial) --> 成员变量的赋值(mark,name) --> 读取有参构造器上方法的值并赋值到当前实例

所以也就不难理解结果为 xx_oo 了, 因为name的赋值操作先于mark的再次赋值, 对指令不了解的可以官网查阅, invokevirtual执行实例化, invokevirtual执行实例的方法

参考

深入理解JVM字节码执行引擎
Oracle JVM官网虚拟机规范

举报

相关推荐

0 条评论