在Java运算中,存在一些关系到顺序的计算,这些计算顺序在C / C++语言中是不确定的,并且最后的结果值也没有保证。不过,Java经过编译之后,生成的是与平台无关的字节码,并且交互对象为Java虚拟机,与底层的硬件环境无关。因此,这些运算结果在Java中是确定的。
从左向右的计算顺序
与C / C++不同的是,在Java中,表达式的计算与结果是确定的。不受硬件环境的影响。例如,一个在C / C++中比较常见例子:
int i = 5;
int j = (i++) + (i++) + (i++);
在C / C++中,变量i与j的值是不确定的,根据不同的开发环境,结果也不相同。例如,在Turbo C中,i的值为8,j的值为15,而在VC中,i的值为8,j的值为18。在Java中,i和j的值是确定的,i为8,j为18。
在Java中,操作数的计算顺序是从左向右的也就是首先会计算左侧的操作数,然后再计算其右侧的操作数。例如:
int a = 3;
int b = a + (++a) + (a = 1) + a;
执行这两个语句之后,a的值为1,b的值为9。因为Java就是从左向右进行计算的,故最后(即最右侧)一条修改a值的表达式为:
a = 1
而第2条语句也就是:
int b = 3 + 4 + 1 + 1;
操作数从左向右的计算规则与运算符的结合性无关,就算运算符是由右向左结合的,也会在运算之前先确定左侧的操作数,请看下面的程序。【例】操作数的确定。
package chapter2;
2.
3. import java.util.Arrays;
4.
5. public class Order {
6. public static void main(String[] args) {
7. int a[] = new int[] {
8. 0, 0, 0, 0, 0, 0
9. };
10. int i = 1;
11. a[++i] = i++;
12. System.out.println("i=" + i);
13. System.out.println(Arrays.toString(a));
14. int j = 3;
15. a[j] = j = 4;
16. System.out.println("j=" + j);
17. System.out.println(Arrays.toString(a));
18. int b[] = new int[] {
19. 9, 9, 9, 9, 9, 9
20. };
21. int k = 5;
22. int c[] = a;
23. a[--k] = (a = b)[k];
24. System.out.println("k=" + k);
25. System.out.println(Arrays.toString(a));
26. System.out.println(Arrays.toString(b));
27. System.out.println(Arrays.toString(c));
28. }
29.}
程序运行结果如下:
i=3
[0, 0, 2, 0, 0, 0]
j=4
[0, 0, 2, 4, 0, 0]
k=4
[9, 9, 9, 9, 9, 9]
[9, 9, 9, 9, 9, 9]
[0, 0, 2, 4, 9, 0]
你预测正确了吗?对于程序第11行:
a[++i] = i++;
虽然赋值运算符是从右向左结合的,但是操作数的确定是从左向右的,也就是在赋值操作发生前,首先会确定左侧的操作数,i的值为1,++i的值就是2,因此,左侧的操作数是a[2],因此,这条语句就相当于:
a[2] = 2;
然后i的值再加1,值为3。第15行的赋值语句:
a[j] = j = 4;
也是同样的道理,首先确定左侧操作数,j的值为3,也就是a[3],这相当于:
a[3] = j = 4;
赋值之后,j和a[3]的值都是4。同样,第23行的语句:
a[--k] = (a = b)[k];
k的值是5,这就相当于:
--k;
int[] temp = a;
a = b;
temp[4] = b[4];
然后,原数组a[4](也就是后来的c[4])的值改变。
复合运算符
我们知道,复合运算符可以自动将右侧运算的结果类型转换为左侧操作数的类型。例如如下的代码:
byte b = 1;
b = b + 1; //错误b += 1; //正确
因为常量1为int类型,所以右侧的结果是int类型,不能赋值给一个byte类型的变量,但是使用复合运算符(+=)是可以的,第3条语句相当于:
b = (byte)(b + 1);
除此之外,复合运算符也有上述的性质,即遵循操作数从左向右计算的原则,也就是说,在执行赋值操作之前,首先会确定左侧的操作数。【例】复合运算符。
1.package chapter2;
2.
3. import java.util.Arrays;
4.
5. public class Order2 {
6. public static void main(String[] args) {
7. int a = 10;
8. a += ++a;
9. System.out.println("a=" + a);
10. int[] array = new int[] {
11. 8, 9, 10
12. };
13. int b = 1;
14. array[b] *= b = 2;
15. System.out.println("b=" + b);
16. System.out.println(Arrays.toString(array));
17. }
18.}
由于有了上面的讲解,这个程序的运行结果应该不难想象了,如下:
a=21
b=2
[8, 18, 10]
总之,运算前会先将左侧的操作数保存起来,左侧的操作数不会受到其右侧表达式的影响而造成改变。
总结:
1.在Java语言中,操作数的计算顺序是从左向右的,即使运算符是从右向左结合的也是如此。
2.与C / C++等语言不同,Java的运算结果受硬件环境的影响很小,计算方式也是确定的。
举一反三
在参数传递的过程中,是否也符合本话题讲述的规则呢?例如下面的程序:
1.package chapter2;
2.
3. public class Order3 {
4. public static void main(String[] args) {
5. Order3 order = new Order3();
6. int i = 10;
7. order.test(i, ++i, i = 2);
8. order.test(i = 5, i++, i);
9. }
10.
11. public void test(int x, int y, int z) {
12. System.out.println(x);
13. System.out.println(y);
14. System.out.println(z);
15. }
16.}
结果是多少呢?自己试试看吧。
本文出自柠檬派http://www.lemonpai.com 请务必保留此出处 ,否则将追究法律责任!