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


    条件判断指令

    指令集合

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

    源码

    package cn.knightzz.jvm.bytecode;
    
    /**
     * @author 王天赐
     * @title: ConditionalJudgmentInstruction
     * @projectName hm-jvm-codes
     * @description: 条件判断指令
     * @website http://knightzz.cn/
     * @github https://github.com/knightzz1998
     * @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;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    字节码

    $ 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."":()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          // "":()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."":()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"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    以上比较指令中没有 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • ifne 判断是否不等于 0 , 如果为true 会直接跳转到 12: bipush 20

    循环控制指令

    源码

    package cn.knightzz.jvm.bytecode;
    
    /**
     * @author 王天赐
     * @title: CyclicControlInstruction
     * @projectName hm-jvm-codes
     * @description: 循环控制指令
     * @website http://knightzz.cn/
     * @github https://github.com/knightzz1998
     * @create: 2022-10-19 19:11
     */
    public class CyclicControlInstruction {
    
        public static void main(String[] args) {
    
            int a = 0;
            while (a < 10) {
                a++;
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    字节码

    $ 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."":()V
       #2 = Class              #21            // cn/knightzz/jvm/bytecode/CyclicControlInstruction
       #3 = Class              #22            // java/lang/Object
       #4 = Utf8               
       #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          // "":()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."":()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"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
       		 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 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 http://knightzz.cn/
     * @github https://github.com/knightzz1998
     * @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
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    字节码

    // 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
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    最终的结果为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 
    24 iload_2
    25 invokevirtual #3 
    28 return
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    Linux性能优化--性能工具:特定进程内存
    企业申请车辆前雾灯E-mark认证的前提条件
    关于Comparable、Comparator接口返回值决定顺序的问题
    图形学-(视图变换,投影变换)
    如何设计实现系统应支持至少300个并行用户的同时访问和使用的需求
    10.20记录纪要
    各类数据引擎指定schema或者数据库
    为什么这么多人转行产品经理?产品经理发展前景如何?
    我的创作纪念日—谈谈我的学习经历
    HTML最快速最简单
  • 原文地址:https://blog.csdn.net/weixin_40040107/article/details/127415737