问题的发现:
在手写归并排序中,写到对原数组进行更新赋值的时候,把t++放在了被赋值数组里面。如图。结果发现程序报数组下标越界了,当把t++放在赋值数组里时,程序就正常运行。
分析
我们都知道,t++中,++放在后面,表示先执行表达式,再执行自增操作。按道理讲
a[t] = tmp[t++]和a[t++] = tmp[t]
应该都是
先执行:a[t] = tmp[t];
再执行:t++;
结果应该是一致的才对,但是上面问题告诉我们,他们并不一样,于是抱着探究到底的精神,我用
javap -c xxx.class
查看了他们的字节码文件到底差别在哪?
理想很美好,显示很残酷~~
如图,我发现自己压根看不懂字节码文件的内容。
思前想后,想到了个好办法,就是把字节码文件反编译过来,再看看看源码有什么区别。
左边是源码,右边是字节码反编译的源码
当a[t] = tmp[t++]
时,程序实际上新增了三个变量,var10001和var10003分别存储两个数组的索引位置且值都是t自增前的值,而var4存储t自增的结果。
当
a[t++] = tmp[t]
时,程序只新增了一个变量,var10001存储a数组的索引位置,且值为t自增前的值,而tmp数组的索引位置直接为t,且值是t自增后的。
看到这里才恍然大悟,上面程序报错的原因了。
总结
1、如果没有必要还是不要装逼在表达式里用自增啦,执行顺序真琢磨不透。还是老老实实的,把语句分开写,想下面这样。
先执行:a[t] = tmp[t];
再执行:t++;
2、在反编译的源码里看到,自增的操作其实优先级是要比赋值操作高的。即使是把t++这样把++写在后面,他只是通过新增变量,来实现我们之前认为的先执行表达式再自增操作。人家早就在你表达式执行前自增完了,只是人家把变量替换了而已。