有如下代码:
public class Main {
public static void main(String[] args) {
int i = 10;
i = i++;
System.out.println(i);
}
}
运行后,发现结果为10,而不是11。这是为什么呢?
首先先介绍一个JDK自带的反编译工具: javap命令。 可以看到到底底层是怎么执行上面的代码的!
先编译Main.java文件
C:\leetcode\src\com\lilike>javac Main.java
此时在Main.java 目录下生成了Main.class文件。
然后执行javap命令:
C:\leetcode\src\com\lilike>javap -c Main
警告: 二进制文件Main包含com.lilike.Main
Compiled from "Main.java"
public class com.lilike.Main {
public com.lilike.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: istore_1
3: iload_1
4: iinc 1, 1
7: istore_1
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: return
}
上面的0,2,3,4,7操作,就是底层i = i ++的执行过程,我们先解释这五项操作,在文章的末尾再补充虚拟机指令的知识。
0: bipush 10 //将参数10压入栈
2:istore_1 //栈中弹出一个数(10),赋值给局部变量i(_1表示赋值给第一个局部变量,即i)
3: iload_1 //将局部变量i(_1表示第一个局部变量,即i)的值入栈,此时栈顶的值为10
4: iinc 1, 1 //指令iinc对给定的局部变量做自增操作
//1,1表示对第一个局部变量i进行累加1操作,意味着i变为了11
7: istore_1 //栈顶弹出一个数:也就是10,赋值给第一个局部变量i。意味着i的值又变回10了。(_1表示赋值给第一个局部变量,即i)
最终打印结果 就是: 10
扩充知识-- java虚拟机指令:
bipush:当int取值-128~127时,JVM采用bipush指令将常量压入栈中。
istore:将栈顶int型数值存入指定本地变量
aload:从局部变量表的相应位置装载一个对象引用到操作数栈的栈顶。还有一些其他相似的操作码用来装载非对象引用,包括iload_、lload_、fload_和dload_,这里的i代表int型,l代表long型,f代表float型以及d代表double型。
iinc:变量自增。