• 字节码详解


    一  通过javap命令查看class文件

     

    TestClass.txt内容如下

    内容大致分为4个部分:
    1. 第一部分:显示了生成这个class的java源文件、版本信息、生成时间等。
    2. 第二部分:显示了该类中所涉及到常量池,共26个常量。
    3. 第三部分:显示该类的构造器,编译器自动插入的。
    4. 第四部分:显示了main方的信息。(这个是需要我们重点关注的)
     1 Classfile /E:/IDEAFile/MyProject/Day01/src/TestClass.class
     2   Last modified 2020-3-11; size 408 bytes
     3   MD5 checksum bb7648f07bfba9e303909f568db45852
     4   Compiled from "TestClass.java"
     5 public class TestClass
     6   minor version: 0
     7   major version: 52
     8   flags: ACC_PUBLIC, ACC_SUPER
     9 Constant pool:        //常量池
    10    #1 = Methodref   //方法引用       #5.#14         // java/lang/Object."<init>":()V
    11    #2 = Fieldref    //字敦引用      #15.#16        // java/lang/System.out:Ljava/io/PrintStream;
    12    #3 = Methodref          #17.#18        // java/io/PrintStream.println:(I)V
    13    #4 = Class       //类       #19            // TestClass
    14    #5 = Class       //UTF-8编码的字符串       #20            // java/lang/Object
    15    #6 = Utf8               <init>
    16    #7 = Utf8               ()V
    17    #8 = Utf8               Code
    18    #9 = Utf8               LineNumberTable
    19   #10 = Utf8               main
    20   #11 = Utf8               ([Ljava/lang/String;)V
    21   #12 = Utf8               SourceFile
    22   #13 = Utf8               TestClass.java
    23   #14 = NameAndType  //字段或方法的符号引用      #6:#7          // "<init>":()V
    24   #15 = Class              #21            // java/lang/System
    25   #16 = NameAndType        #22:#23        // out:Ljava/io/PrintStream;
    26   #17 = Class              #24            // java/io/PrintStream
    27   #18 = NameAndType        #25:#26        // println:(I)V
    28   #19 = Utf8               TestClass
    29   #20 = Utf8               java/lang/Object
    30   #21 = Utf8               java/lang/System
    31   #22 = Utf8               out
    32   #23 = Utf8               Ljava/io/PrintStream;
    33   #24 = Utf8               java/io/PrintStream
    34   #25 = Utf8               println
    35   #26 = Utf8               (I)V
    36 {
    37   public TestClass();    //无参构造
    38     descriptor: ()V        //返回值类型
    39     flags: ACC_PUBLIC
    40     Code:        //栈大小,局部变量表大小,参数个数
    41       stack=1, locals=1, args_size=1
    42          0: aload_0
    43          1: invokespecial #1                  // Method java/lang/Object."<init>":()V
    44          4: return
    45       LineNumberTable:
    46         line 1: 0
    47 
    48   public static void main(java.lang.String[]);
    49     descriptor: ([Ljava/lang/String;)V
    50     flags: ACC_PUBLIC, ACC_STATIC
    51     Code:
    52       stack=2, locals=4, args_size=1
    53          0: iconst_2                //将int类型的2压入栈        
    54          1: istore_1                //出栈一个变量放入局部变量表中下标为1的位置,下标为0的位置存放的是this指针,此时栈为空,
    55          2: iconst_5                //将int类型的5压入栈
    56          3: istore_2                //出栈一个变量放入局部变量表中下标为2的位置,下标为0的位置存放的是this指针,此时栈为空,
    57          4: iload_2                 //从局部变量表中取出下标为2(实际值此处为5)的变量压入操作数栈中
    58          5: iload_1                 //从局部变量表中取出下标为1(实际值此处为2)的变量压入操作数栈中
    59          6: isub                    //在操作数栈中做减操作,结果为3
    60          7: istore_3                //出栈一个变量放入局部变量表中下标为3的位置,下标为0的位置存放的是this指针,此时栈为空,
    61          8: getstatic     #2        //去常量池中引用"#2"符号引用的类与方法          Field java/lang/System.out:Ljava/io/PrintStream;
    62         11: iload_3                 //从局部变量表中取出下标为3(实际值此处为3)的变量压入操作数栈中
    63         12: invokevirtual #3        //调度对象的实现方法          Method java/io/PrintStream.println:(I)V
    64         15: return
    65       LineNumberTable:
    66         line 3: 0
    67         line 4: 2
    68         line 5: 4
    69         line 6: 8
    70         line 7: 15
    71 }
    72 SourceFile: "TestClass.java"

      常量池

      Constant               TypeValue      说明
    • CONSTANT_Class          7        类或接口的符号引用
    • CONSTANT_Fieldref            9        字段的符号引用
    • CONSTANT_Methodref          10        类中方法的符号引用
    • CONSTANT_InterfaceMethodref       11        接口中方法的符号引用
    • CONSTANT_String          8        字符串类型常量
    • CONSTANT_Integer           3        整形常量
    • CONSTANT_Float            4        浮点型常量
    • CONSTANT_Long            5        长整型常量
    • CONSTANT_Double           6        双精度浮点型常量
    • CONSTANT_NameAndType      12        字段或方法的符号引用
    • CONSTANT_Utf8            1         UTF-8编码的字符串
    • CONSTANT_MethodHandle      15        表示方法句柄
    • CONSTANT_MethodType       16        标志方法类型
    • CONSTANT_InvokeDynamic       18        表示一个动态方法调用点

    二  i++和++i的区别

        类:

     

      使用javap命令后

        i++

      public void mot1();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=3, args_size=1
             0: iconst_1                    //将int类型的1压入栈
             1: istore_1                    //出栈一个变量放入局部变量表中下标为1的位置,下标为0的位置存放的是this指针,此时栈为空
             2: iload_1                        //从局部变量表中取出下标为1(实际值此处为1)的变量压入操作数栈中
             3: iinc          1, 1            //将局部变量表中下标为1的变量进行加1操作
             6: istore_2                    //出栈一个变量放入局部变量表中下标为2的位置,这一步没有对操作栈中的数进行操作,直接出栈到变量表中
             7: getstatic     #6            //去常量池中引用"#6"符号引用的类与方法 Field java/lang/System.out:Ljava/io/PrintStream;
            10: iload_2                        //从局部变量表中取出下标为1(实际值此处为1)的变量压入操作数栈中
            11: invokevirtual #7            //执行println方法    Method java/io/PrintStream.println:(I)V
            14: return
          LineNumberTable:
            line 8: 0
            line 9: 2
            line 10: 7
            line 12: 14

      ++i

      public void mot2();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=3, args_size=1
             0: iconst_1                //将int类型的1压入栈
             1: istore_1                //出栈一个变量放入局部变量表中下标为1的位置,下标为0的位置存放的是this指针,此时栈为空
             2: iinc          1, 1        //将局部变量表中下标为1的变量进行加1操作
             5: iload_1                    //从局部变量表中取出下标为1(实际值此处为2)的变量压入操作数栈中
             6: istore_2                //出栈一个变量放入局部变量表中下标为2的位置,(实际值此处为2)
             7: getstatic     #6         //去常量池中引用"#6"符号引用的类与方法  Field java/lang/System.out:Ljava/io/PrintStream;
            10: iload_2                    //从局部变量表中取出下标为1(实际值此处为2)的变量压入操作数栈中
            11: invokevirtual #7        //执行println方法       Method java/io/PrintStream.println:(I)V
            14: return
          LineNumberTable:
            line 15: 0
            line 16: 2
            line 17: 7
            line 19: 14

    区别:

      i++

      •   只是在本地变量中对数字做了相加,并没有将数据压入到操作栈
      •   将前面拿到的数字1,再次从操作栈中拿到,压入到本地变量中

      ++i

      •   将本地变量中的数字做了相加,并且将数据压入到操作栈
      •   将操作栈中的数据,再次压入到本地变量中
  • 相关阅读:
    jenkins
    k8s 驱逐限制
    jenkins+k8s 实现持续集成
    镜像更新备份
    【工具分享】2020年4月 phpstorm2020.1 for mac
    【排坑】mac安装homebrew会遇到的各种问题解决方案
    记一次C盘扩容
    2018夏季工作台之再设计
    left join后面加上where条件浅析
    编程随想篇(2018夏)
  • 原文地址:https://www.cnblogs.com/wangdayexinyue/p/12463944.html
Copyright © 2020-2023  润新知