有如下示例:
public class Demo {
public static void main(String[] args) {
int i = 1;
i = i++;
int j = i++;
int k = i+ ++i * i++;
System.out.println("i="+i);
System.out.println("j="+j);
System.out.println("k="+k);
}
}
进行反编译查看字节码指令:javap -v Demo.class
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
// locals=4,表明局部变量表中包含4个slot
// stack=3,操作数栈的深度为3
stack=3, locals=4, args_size=1
0: iconst_1 // 当int取值-1~5时,采用指令iconst将常量1压入栈中
1: istore_1 // 将操作数栈顶的元素取出,保存到局部变量表slot=1的位置,相当于int i= 1;的赋值操作
2: iload_1 // 将局部变量表中slot=1的变量压入操作数栈,准备对i变量进行运算
3: iinc 1, 1 // 将局部变量表中slot=1的值,进行自增操作,自增的值为后面的1
6: istore_1 // 将操作数栈顶的元素取出,保存到局部变量表slot=1的位置
7: iload_1 // 将局部变量表中slot=1的变量压入操作数栈,准备对i变量进行运算
8: iinc 1, 1 // 自增
11: istore_2 // 将操作数栈顶的元素取出,保存到局部变量表slot=1的位置,相当于int j= i++;的赋值操作
12: iload_1 // 将局部变量表中slot=1的变量压入操作数栈,准备对i变量进行运算
13: iinc 1, 1 // 将局部变量表中slot=1的值,进行自增操作,自增的值为后面的1
16: iload_1 // 将局部变量表中slot=1的变量压入操作数栈,此时相当于准备使用++i,进行运算了
17: iload_1 // 将局部变量表中slot=1的变量压入操作数栈,准备对i++进行运算,因为它是先运算后加加,所以先入栈,再自增
18: iinc 1, 1 // 对i进行自增,相当于i++
21: imul // 将取出两个栈顶元素,进行乘法运算,并将结果压入栈顶
22: iadd // 将取出两个栈顶元素,进行加法运算,并将结果压入栈顶
23: istore_3 // 将操作数栈顶的元素取出,保存到局部变量表slot=3的位置,相当于int k = i+ ++i * i++;的赋值操作
24: getstatic #2
现在,我们从指令3开始看:iinc 1, 1,在局部变量表中对slot=1的值进行自增1,相当于代码:i++ 注意:自增操作在局部变量表中进行
指令6执行后,又将操作数栈顶元素取出,存到了slot=1的局部变量表的位置,相当于 i = i++,这个赋值操作,也就是说此时i = 1
指令7,将slot=1的值压入栈顶;来到指令8,和指令3一样,又进行了一次自增操作 i++
指令11,将操作数栈顶元素取出,放到slot=2的位置,相当于对int j的赋值操作,此时j=1
指令13又对,slot=1位置的值进行了自增操作,相当于++i,此时:
执行到指令18时,已经将i,++i,i++完成了入栈操作,并对i进行了后++操作
指令21,分别取出了栈顶的3,3,并将他们进行乘法运算,然后压入栈顶,相当于++i * i++
指令22,取出栈顶元素,相加后,将结果压入栈中,相当于(i+ ++i * i++),
最后,指令23,给变量k进行赋值
那么经过上述分析,结果显而易见
i = 1; j = 1; k = 11;
是不是呢?(没有p图哦,嘻嘻)是的
最后总结:自增在变量,运算在栈中,栈中运算完,赋值变量中。赋值操作要最后完成。