Mar*_*ius 45 java operator-precedence post-increment ocpjp
我正在攻读OCPJP考试,因此我必须了解Java的每一个奇怪的细节.这包括增量前和增量后运算符应用于变量的顺序.以下代码给出了奇怪的结果:
int a = 3;
a = (a++) * (a++);
System.out.println(a); // 12
Run Code Online (Sandbox Code Playgroud)
答案不应该是11吗?或者13?但不是12!
跟进:
以下代码的结果是什么?
int a = 3;
a += (a++) * (a++);
System.out.println(a);
Run Code Online (Sandbox Code Playgroud)
Boz*_*zho 110
在第一次a++ a成为4.所以你有3 * 4 = 12.
(a在第2次之后变为5 a++,但是被丢弃,因为赋值a =会覆盖它)
Rok*_*alj 31
你的陈述:
a += (a++) * (a++);
Run Code Online (Sandbox Code Playgroud)
相当于以下任何一个:
a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)
Run Code Online (Sandbox Code Playgroud)
请改用其中任何一种.
the*_*oop 25
a++表示'a的值,然后a增加1'.所以当你跑步
(a++) * (a++)
Run Code Online (Sandbox Code Playgroud)
首先a++评估第一个,然后产生值3. a然后增加1. a++然后评估第二个.a产生值4,然后再次递增(但现在这没关系)
所以这变成了
a = 3 * 4
Run Code Online (Sandbox Code Playgroud)
等于12.
int a = 3;
a += (a++) * (a++);
Run Code Online (Sandbox Code Playgroud)
首先构建语法树:
+=
a
*
a++
a++
Run Code Online (Sandbox Code Playgroud)
要评估它从最外层的元素开始并递归下降.对于每个元素做:
该+=运营商是特殊的:它被扩展到类似left = left + right,但只计算表达式left一次.在右侧被评估为值之前,左侧仍被评估为值(而不仅仅是变量).
这导致:
+=a.a的值3.*a++.这将返回a的当前值3并设置a为4a++.这将返回a的当前值4并设置a为5+=.左侧3在第三步评估,右侧评估12.所以它指定3 + 12 = 15 a.a是15.这里需要注意的一点是,运算符优先级对评估顺序没有直接影响.它只会影响树的形式,从而间接影响顺序.但是在树中的兄弟姐妹中,无论运算符优先级如何,评估始终是从左到右.
(a++) 是一个后增量,因此表达式的值为3.
(a++) 是后增量,所以表达式的值现在是4.
表达评估从左到右进行.
3 * 4 = 12
Run Code Online (Sandbox Code Playgroud)
对操作员的工作原理普遍缺乏了解.老实说,每个操作员都是语法糖.
您所要做的就是了解每个操作员背后的实际情况.假设如下:
a = b -> Operators.set(a, b) //don't forget this returns b
a + b -> Operators.add(a, b)
a - b -> Operators.subtract(a, b)
a * b -> Operators.multiply(a, b)
a / b -> Operators.divide(a, b)
Run Code Online (Sandbox Code Playgroud)
然后可以使用这些概括来重写复合运算符(为简单起见,请忽略返回类型):
Operators.addTo(a, b) { //a += b
return Operators.set(a, Operators.add(a, b));
}
Operators.preIncrement(a) { //++a
return Operators.addTo(a, 1);
}
Operators.postIncrement(a) { //a++
Operators.set(b, a);
Operators.addTo(a, 1);
return b;
}
Run Code Online (Sandbox Code Playgroud)
你可以重写你的例子:
int a = 3;
a = (a++) * (a++);
Run Code Online (Sandbox Code Playgroud)
如
Operators.set(a, 3)
Operators.set(a, Operators.multiply(Operators.postIncrement(a), Operators.postIncrement(a)));
Run Code Online (Sandbox Code Playgroud)
哪个可以使用多个变量拆分:
Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))
Run Code Online (Sandbox Code Playgroud)
这种方式肯定更加冗长,但很明显,您永远不会想要在一条线上执行两次以上的操作.
的情况下 :
int a = 3;
a = (a++) * (a++);
a = 3 * a++; now a is 4 because of post increment
a = 3 * 4; now a is 5 because of second post increment
a = 12; value of 5 is overwritten with 3*4 i.e. 12
Run Code Online (Sandbox Code Playgroud)
的情况下 :
a += (a++) * (a++);
a = a + (a++) * (a++);
a = 3 + (a++) * (a++); // a is 3
a = 3 + 3 * (a++); //a is 4
a = 3 + 3 * 4; //a is 5
a = 15
Run Code Online (Sandbox Code Playgroud)
这里要注意的要点是,在这种情况下,编译器从左到右求解,并且在后增量的情况下,增量前的值用于计算,并且当我们从左向右移动时,使用递增的值.