条件判断指令分析 || JVM类加载与字节码技术

条件判断指令

指令集合

image-20221019182650459
  • byte,short,char 都会按 int 比较,因为操作数栈都是 4 字节
  • goto 用来进行跳转到指定行号的字节码

源码

package cn.knightzz.jvm.bytecode;

/**
 * @author 王天赐
 * @title: ConditionalJudgmentInstruction
 * @projectName hm-jvm-codes
 * @description: 条件判断指令
 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
 * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
 * @create: 2022-10-19 18:53
 */
public class ConditionalJudgmentInstruction {

    public static void main(String[] args) {
        int a = 0;
        if (a == 0) {
            a = 10;
        } else {
            a = 20;
        }
    }
}

字节码

$ javap -v ConditionalJudgmentInstruction.class 
Classfile /F:/JavaCode/hm-jvm-codes/jvm-chapter-03/target/classes/cn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction.class
  Last modified 2022-10-19; size 561 bytes
  MD5 checksum 4cb9364c4df2604d19885ce96894b9d9
  Compiled from "ConditionalJudgmentInstruction.java"
public class cn.knightzz.jvm.bytecode.ConditionalJudgmentInstruction
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#20         // java/lang/Object."<init>":()V
   #2 = Class              #21            // cn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction
   #3 = Class              #22            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction;
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               args
  #14 = Utf8               [Ljava/lang/String;
  #15 = Utf8               a
  #16 = Utf8               I
  #17 = Utf8               StackMapTable
  #18 = Utf8               SourceFile
  #19 = Utf8               ConditionalJudgmentInstruction.java
  #20 = NameAndType        #4:#5          // "<init>":()V
  #21 = Utf8               cn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction
  #22 = Utf8               java/lang/Object
{
  public cn.knightzz.jvm.bytecode.ConditionalJudgmentInstruction();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: ifne          12
         6: bipush        10
         8: istore_1
         9: goto          15
        12: bipush        20
        14: istore_1
      StackMapTable: number_of_entries = 2
        frame_type = 252 /* append */
          offset_delta = 12
          locals = [ int ]
        frame_type = 2 /* same */
}
SourceFile: "ConditionalJudgmentInstruction.java"

以上比较指令中没有 long,flfloat,double 的比较,那么它们要比较怎么办 ?

参考 : https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.lcmp

核心的字节码 :

		 0: iconst_0
         1: istore_1
         2: iload_1
         3: ifne          12
         6: bipush        10
         8: istore_1
         9: goto          15
        12: bipush        20
        14: istore_1
        15: return
  • ifne 判断是否不等于 0 , 如果为true 会直接跳转到 12: bipush 20

循环控制指令

源码

package cn.knightzz.jvm.bytecode;

/**
 * @author 王天赐
 * @title: CyclicControlInstruction
 * @projectName hm-jvm-codes
 * @description: 循环控制指令
 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
 * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
 * @create: 2022-10-19 19:11
 */
public class CyclicControlInstruction {

    public static void main(String[] args) {

        int a = 0;
        while (a < 10) {
            a++;
        }

    }
}

字节码

$ javap -v CyclicControlInstruction.class 
Classfile /F:/JavaCode/hm-jvm-codes/jvm-chapter-03/target/classes/cn/knightzz/jvm/bytecode/CyclicControlInstruction.class
  Last modified 2022-10-19; size 538 bytes
  MD5 checksum 1d37128d3ea691714bb95fcb7f1edec9
  Compiled from "CyclicControlInstruction.java"
public class cn.knightzz.jvm.bytecode.CyclicControlInstruction
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#20         // java/lang/Object."<init>":()V
   #2 = Class              #21            // cn/knightzz/jvm/bytecode/CyclicControlInstruction
   #3 = Class              #22            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcn/knightzz/jvm/bytecode/CyclicControlInstruction;
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               args
  #14 = Utf8               [Ljava/lang/String;
  #15 = Utf8               a
  #16 = Utf8               I
  #17 = Utf8               StackMapTable
  #18 = Utf8               SourceFile
  #19 = Utf8               CyclicControlInstruction.java
  #20 = NameAndType        #4:#5          // "<init>":()V
  #21 = Utf8               cn/knightzz/jvm/bytecode/CyclicControlInstruction
  #22 = Utf8               java/lang/Object
{
  public cn.knightzz.jvm.bytecode.CyclicControlInstruction();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/knightzz/jvm/bytecode/CyclicControlInstruction;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush        10
         5: if_icmpge     14
         8: iinc          1, 1
        11: goto          2
        14: return
      LineNumberTable:
        line 16: 0
        line 17: 2
        line 18: 8
        line 21: 14
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      15     0  args   [Ljava/lang/String;
            2      13     1     a   I
      StackMapTable: number_of_entries = 2
        frame_type = 252 /* append */
          offset_delta = 2
          locals = [ int ]
        frame_type = 11 /* same */
}
SourceFile: "CyclicControlInstruction.java"

   		 0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush        10
         5: if_icmpge     14
         8: iinc          1, 1
        11: goto          2
        14: return
  • iconst_0 创建一个值为 0 的常量
  • istore_1 赋值给 插槽1的变量 a
  • iload_1 将a的值压入栈
  • bipush 10 将10压入栈
  • if_icmpge : 判断两个int是否 >= ==> a >= 10
    • 如果为true , 直接跳到 14:return
    • 如果为false, iinc 1,1 => 插槽1中的元素a累加1
    • goto 2 ==> 2: iload_1

其他的如 do while 和 for 其实都是类似的

练习-判断结果

源码

package cn.knightzz.jvm.bytecode;

/**
 * @author 王天赐
 * @title: JudgementResult
 * @projectName hm-jvm-codes
 * @description: 判断结果
 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
 * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
 * @create: 2022-10-19 19:22
 */
public class JudgementResult {

    public static void main(String[] args) {

        int i = 0;
        int x = 0;
        while (i < 10) {
            x = x++;
            i++;
        }
        System.out.println(x); // 结果是 0

    }
}

字节码

// int i = 0
iconst_0
istore_1
// int x = 0
iconst_0
istore_2

iload_1
bipush 10
if_icmpge     xxx

iload_2  // 将 0 加载进操作数栈
iinc 2,1 // 直接在局部变量表中累加
istore_2 // 将操作数栈中的元素 0 重新赋值到 x(slot_2) 
iload_1
iinc 1,1
goto xxx

getstatic #x
invoke xx



最终的结果为0的原因是因为 :

  • iload_2 ==> 将 0 加载进操作数栈
  • iinc 2,1 ==> 直接在局部变量表中累加 , 此时 x = 1
  • istore_2 // 将操作数栈中的元素 0 重新赋值到 x(slot_2) 此时 x = 0

赋值指令是从操作数栈复制到局部变量表中 , 而累加是 直接在局部变量表中累加

生成的字节码 :

 0 iconst_0
 1 istore_1
 2 iconst_0
 3 istore_2
 4 iload_1
 5 bipush 10
 7 if_icmpge 21 (+14)
10 iload_2
11 iinc 2 by 1
14 istore_2
15 iinc 1 by 1
18 goto 4 (-14)
21 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
24 iload_2
25 invokevirtual #3 <java/io/PrintStream.println : (I)V>
28 return

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兀坐晴窗独饮茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值