相信不少从事java开发的人在刚开始接触java的时候都会遇到让人巨头疼的i++和++i问题,网上很多资料都是直接告诉结果而并没有说清楚为什么是这个结果,包括自己之前也是死记硬背,知其然不知其所以然,碰巧前几天在网上看到javap命令,现在在这里做一个小的总结,也顺便用这个命令来带大家从字节码的角度解析一下这虚拟机是如何处理这两个不同的命令的。
- **首先来看下面这道题 **
public class Test{
public static void main(String[] args){
int n = 0;
for(int i = 0; i < 100; i++){
n = n++;
}
System.out.println(n);
}
}
你觉得结果是什么呢,是100,还是0。如果你对自己的结果不确信或者知道结果但是不知道为什么是这个结果的。请往下看。
javap是什么
具体定义请自行Google,我只知道javap -c
可以让我们看到编译后产生的字节码,对照源码和字节码会清楚很多。
- 与javap的第一次邂逅
public class Test{
public static void main(String[] args){
int i = 5;
}
}
为方便起见,这里只看main部分的字节码
public static void main(java.lang.String[]);
Code:
0: iconst_5 //将常量5入栈
1: istore_1 //将栈顶的弹出,并存储在位置1的局部变量中,即"i"中
2: return
是不是很简单,那我们来个稍微复杂点的
public class Test{
public static void main(String[] args){
int i = 5;
int j = i;
}
}
public static void main(java.lang.String[]);
Code:
0: iconst_5 //把常量5入栈
1: istore_1 //将栈顶的值弹出,并存储在位置1的局部变量中,即"i"中 ,此时"i"的值为5
2: iload_1 //把位置1的局部变量压入栈中
3: istore_2 //把栈顶的值弹出,并存储在位置2的局部变量中,即"j"中,此时"j"的值为5
4: return
怎么样,也不难是吧,终于轮到我们的大boss出场了
- i++&++i
public class Test{
public static void main(String[] args){
int i = 5;
i = i++;
int j = 6;
j = ++j;
}
}
最终结果 i = 5,j = 7!
public static void main(java.lang.String[]);
Code:
0: iconst_5 //把常量5入栈
1: istore_1 //将栈顶的值弹出并存储在位置1的局部变量1中,即"i"中,此时"i"的值为5
2: iload_1 //将位置1的局部变量压入栈,即"i"入栈,栈顶值为5
3: iinc 1, 1 //将位置1的值加1,即"i"加1,此时"i"的值为6,注意这条指令不会改变栈顶的值
6: istore_1 //将栈顶的值弹出并存储在位置1的局部变量中,即"i"中,此时"i"的值依然为5
7: bipush 6 //将常量6入栈
9: istore_2 //将栈顶的值弹出并存储在位置2的局部变量中,即"j"中,此时"j"的值为6
10: iinc 2, 1 //将位置2的值加1,即"j"加1,此时"j"的值为7,注意这条指令不会改变栈顶的值
13: iload_2 //将位置2的局部变量压入栈,即"j"入栈,栈顶值为7
14: istore_2 //将栈顶的值弹出并存储在位置2的局部变量中,即"j"中,此时"j"的值为7
15: return
从字节码中我么可以看出i++与++i的主要区别在于步骤2,3与步骤10,11的顺序是相反的,这是造成了最终解结果不同最终原因。
- 对于i++是先把i的值存在栈顶,然后i自增1,最后把栈顶的值赋给i,所以相当与如下代码:
int temp = i;
i++;
i = temp;
- 而对于++i来说呢,是i先自增1,然后在把i的值存入栈顶,最后把栈顶的值赋给i。
看到这里你是不是对本文开始的题目理解的更透彻了呢!
THE END
如有错误之处还请大家不吝赐教,多多指正,共同进步!
网友评论