探索字节码底层i++和++i的区别
1.查看代码的字节码文件
这是一个java文件
编译java文件
就会生成一个class文件
使用命令javap -v 获取字节码文件重定向到Test1.txt这个文件中
打开这个txt文件
Classfile /C:/Users/Administrator/Desktop/Test1.class
Last modified 2019-4-17; size 572 bytes
MD5 checksum ddb31aefaec5e019f1f6e133b22ea966
Compiled from "Test1.java"
public class Test1
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #8.#19 // java/lang/Object."<init>":()V
#2 = Class #20 // Test1
#3 = Methodref #2.#19 // Test1."<init>":()V
#4 = Methodref #2.#21 // Test1.method1:()V
#5 = Methodref #2.#22 // Test1.method2:()V
#6 = Fieldref #23.#24 // java/lang/System.out:Ljava/io/PrintStream;
#7 = Methodref #25.#26 // java/io/PrintStream.println:(I)V
#8 = Class #27 // java/lang/Object
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 method1
#16 = Utf8 method2
#17 = Utf8 SourceFile
#18 = Utf8 Test1.java
#19 = NameAndType #9:#10 // "<init>":()V
#20 = Utf8 Test1
#21 = NameAndType #15:#10 // method1:()V
#22 = NameAndType #16:#10 // method2:()V
#23 = Class #28 // java/lang/System
#24 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
#25 = Class #31 // java/io/PrintStream
#26 = NameAndType #32:#33 // println:(I)V
#27 = Utf8 java/lang/Object
#28 = Utf8 java/lang/System
#29 = Utf8 out
#30 = Utf8 Ljava/io/PrintStream;
#31 = Utf8 java/io/PrintStream
#32 = Utf8 println
#33 = Utf8 (I)V
{
public Test1();
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 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V //方法描述,V表示该方法的放回值为void
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #2 // class Test1
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method method1:()V
10: new #2 // class Test1
13: dup
14: invokespecial #3 // Method "<init>":()V
17: invokevirtual #5 // Method method2:()V
20: return
LineNumberTable:
line 3: 0
line 4: 10
line 6: 20
public void method1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1 // stack=2,操作栈的大小为2、locals=3,本地变量表大小,args_size=1, 参数
的个数
0: iconst_1 //将数字1压入到操作栈
1: istore_1 //将数字1从操作栈弹出,压入到本地变量表中,下标为1
2: iload_1 //从本地变量表中获取下标为1的数据,压入到操作栈中
3: iinc 1, 1 // 将本地变量中的1,再+1
6: istore_2 // 将数字1从操作栈弹出,压入到本地变量表中,下标为2
7: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_2 //从本地变量表中获取下标为2的数据,压入到操作栈中
11: invokevirtual #7 // Method java/io/PrintStream.println:(I)V
14: return //结束
LineNumberTable:
line 8: 0
line 9: 2
line 10: 7
line 11: 14
public void method2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: iconst_1 //将数字1压入到操作栈
1: istore_1 //将数字1从操作栈弹出,压入到本地变量表中,下标为1
2: iinc 1, 1 // 将本地变量中的1,再+1
5: iload_1 //从本地变量表中获取下标为1的数据(2),压入到操作栈中
6: istore_2 //将数字2从操作栈弹出,压入到本地变量表中,下标为2
7: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_2 //从本地变量表中获取下标为2的数据(2),压入到操作栈中
11: invokevirtual #7 // Method java/io/PrintStream.println:(I)V
14: return //结束
LineNumberTable:
line 13: 0
line 14: 2
line 15: 7
line 16: 14
}
SourceFile: "Test1.java"
内容大致分为4个部分:
第一部分:显示了生成这个class的java源文件、版本信息、生成时间等。
第二部分:显示了该类中所涉及到常量池,共35个常量。
第三部分:显示该类的构造器,编译器自动插入的。
第四部分:显示了main方的信息。(这个是需要我们重点关注的)
常量池
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4-140
2.查看具体代码逻辑
具体什么意思我在上面都有文字说明
3.画图解释
文字有可能说不明白,下面画图解释
i++
++i我就不再做了,可以自己尝试一下
纯手写点个赞!