前言
最近越来越感觉到java基础的重要性,开始重新拾起封存已久的《Thinking in java》,偶然的一个小案例引发了此次的思考。
Demo
首先一个小的demo:
public class Test {
public static void main(String[] args) {
int a = 1;
System.out.println("1:"+ a);
a++;
System.out.println("2:"+ a);
++a;
System.out.println("3:"+ a);
a = ++a;
System.out.println("4:"+ a);
a = a++;
System.out.println("5:"+ a);
a = a++ + ++a;
System.out.println("6:"+ a);
int b = a++;
System.out.println("7:"+ a);
System.out.println("8:"+ b);
}
}
java入门时都会遇到过的小案例,前三个答案相信都会随口而出,但是第四个才是此次探索的问题所在,上面答案如下:
1:1
2:2
3:3
4:4
5:4
6:10
7:11
8:10
回答正确的可以绕过本篇文章,回答错误的跟笔者一起探索下去吧。
代码分析
- a++ 和 ++a 区别不在过多赘述,a++是先执行表达式后++,++a是先++再执行表达式。
- a = ++a; 从上的结果可以得出a=3,此时a先++等于4,再赋值给a。此时a=4无异议。
- a = a++; 从上的结果可以得出a=4,此时a先被赋值为4,再执行++,此时a=5。为什么++未生效呢?这篇文章主要就是这个问题的探讨,具体原因可以参考下面对jVM的分析。
- a = a++ + a++; 从上的结果可以得出a=4,运算时第一个a仍为4,然后经过a++为5,又因为++a先执行++,此时a=6,所以结果4+6=10。
- b = a++; 从上的结果可以得出a=10,此时b先被a赋值为10,a再执行++为11。对比上面的第三点,此时++也生效,什么原因?见JVM分析。
JVM分析
上述Demo可以通过java自带的javap查看字节码文件,命令如下:
javac Test.java
javap -c Test.class
觉得分不清的可以分别对语句进行查看字节码文件,以下是笔者的探索过程。
a++和++a的字节码分析(两个字节码基本相同):
0: iconst_1 1压入栈顶 1: istore_1 栈顶值(1)存入局部变量1(a) 2: iinc 1, 1 变量1自加(a++或++a操作,自加后变量1的值为2)
a=++a的字节码分析:
0: iconst_3 3压入栈顶 1: istore_1 栈顶值(3)存入局部变量1(a) 2: iinc 1, 1 变量1自加(++a操作,自加后变量1的值为4) 5: iload_1 变量1的值压入栈顶(值为4) 6: istore_1 将栈顶值(4)存入变量1(=操作)
a=a++的字节码分析:
0: iconst_4 4压入栈顶 1: istore_1 栈顶值(4)存入局部变量1(a) 2: iload_1 变量1的值压入栈顶(值为4) 3: iinc 1, 1 变量1自加(a++操作,自加后变量1的值为5) 6: istore_1 将栈顶值(4)存入变量1(=操作)
b=a++的字节码分析:
0: bipush 10 10压入栈顶 2: istore_1 栈顶值(10)存入局部变量1(a) 3: iload_1 变量1的值压入栈顶(值为10) 4: iinc 1, 1 变量1自加(a++操作,自加后变量1的值为11) 7: istore_2 栈顶值(10)存入局部变量2(b)(=操作)
从3可以看出a=a++,a++操作后并没有压入栈,返回a的值为栈顶值4,所以a从5又被赋值为4。对于1,2本质上只是对变量操作,并没有计算的赋值逻辑,对于4,变量b被赋值栈顶值为10,变量a自加后为11。以上为思考全过程,如果不足请指正。