美文网首页
《深入拆解Java 虚拟机》专栏

《深入拆解Java 虚拟机》专栏

作者: Wi1ls努力努力再努力 | 来源:发表于2019-04-22 11:56 被阅读0次

第二课时;

public static void main(String[] args) {
    boolean flag = true;
    if (flag) {
      System.out.println("hello,java");
    }
    if (flag == true) {
      System.out.println("Hello,jvm");
    }
  }

在 javac 编译后,翻译为

         0: iconst_1
         1: istore_1
         2: iload_1
         3: ifeq          14
         6: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: ldc           #3                  // String hello,java
        11: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        14: iload_1
        15: iconst_1
        16: if_icmpne     27
        19: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        22: ldc           #5                  // String Hello,jvm
        24: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        27: return
//boolean flag  = true翻译为,入参args在 slot编号为0的位置,flag在 slot 编号为1的部分,true 在虚拟机以1的形式存在
iconst_1
istore_1
//将 slot 编号为1,即 flag 压栈,ifeg 14的意思是如果栈顶元素为0,则跳转到14行,即if(flag)在虚拟机被翻译为flag!=0则执行
iload_1
ifeq 14
...
//将flag压栈,将int值1压栈,if_icmpne 27的意思是比较栈顶两个 int 值大小,不等于0则跳转到27行,所以if(flag == true)被虚拟机翻译为相等则执行
iload_1
iconst_1
if_icmpne 27

从上面可以看到,boolean在虚拟机以 int 的形式存在,并且true翻译为1,false翻译为0, if(flag)是与0比,不相等则执行, if(flag == true)是与1比,相等则执行。
可以用二进制打开.class文件,将第0行的iconst_1的字节码 code 由0x04改为0x05验证试验。


第三课时;

public class Test {
  static boolean flag = true;
  
  public static void main(String[] args) {
    flag = true;
    if (flag) {
      System.out.println("hello,java");
    }
    if (flag) {
      System.out.println("Hello,jvm");
    }
  }
}

main()的字节码

        0: iconst_1
         1: putstatic     #2                  // Field flag:Z
         4: getstatic     #2                  // Field flag:Z
         7: ifeq          18
        10: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        13: ldc           #4                  // String hello,java
        15: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        18: getstatic     #2                  // Field flag:Z
        21: ifeq          32
        24: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        27: ldc           #6                  // String Hello,jvm
        29: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        32: return

实验是利用修改.class文件,将iconst_1对应的字节码code 0x04修改为0x05(iconst_2)和0x06(iconst_3),然后执行。
可以发现当为0x05时(iconst_2),发现ife不满足(即flag为0),但是发现没有执行。当位0x06(iconst_3),发现ifeq是满足的(即 flag 为1)。究其原因是因为 flag 是静态变量,其field flag 是 Z,因此在 putstatic的时候进行了掩码操作。如果直接通过 Unsafe 直接操作内存,会发现可以将 flas 设置为期望的值。

相关文章

网友评论

      本文标题:《深入拆解Java 虚拟机》专栏

      本文链接:https://www.haomeiwen.com/subject/bpcygqtx.html