字节码详解

一  通过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

    •   将本地变量中的数字做了相加,并且将数据压入到操作栈
    •   将操作栈中的数据,再次压入到本地变量中
原文地址:https://www.cnblogs.com/wangdayexinyue/p/12463944.html