字节码详解
一 通过javap命令查看class文件
TestClass.txt内容如下
内容大致分为4个部分:
- 第一部分:显示了生成这个class的java源文件、版本信息、生成时间等。
- 第二部分:显示了该类中所涉及到常量池,共26个常量。
- 第三部分:显示该类的构造器,编译器自动插入的。
- 第四部分:显示了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
-
- 将本地变量中的数字做了相加,并且将数据压入到操作栈
- 将操作栈中的数据,再次压入到本地变量中
WangDaYe