a=(a+;+;)*(a+;+;)在Java中给出了奇怪的结果
我正在准备OCPJP考试,所以我必须理解Java的每一个奇怪的细节。这包括增量前和增量后运算符应用于变量的顺序。以下代码给了我奇怪的结果:a=(a+;+;)*(a+;+;)在Java中给出了奇怪的结果,java,post-increment,operator-precedence,ocpjp,Java,Post Increment,Operator Precedence,Ocpjp,我正在准备OCPJP考试,所以我必须理解Java的每一个奇怪的细节。这包括增量前和增量后运算符应用于变量的顺序。以下代码给了我奇怪的结果: int a = 3; a = (a++) * (a++); System.out.println(a); // 12 答案不应该是11吗?或者13岁?但不是12岁 跟进: 以下代码的结果是什么 int a = 3; a += (a++) * (a++); System.out.println(a); 你的声明: a += (a++) * (a++
int a = 3;
a = (a++) * (a++);
System.out.println(a); // 12
答案不应该是11吗?或者13岁?但不是12岁
跟进:
以下代码的结果是什么
int a = 3;
a += (a++) * (a++);
System.out.println(a);
你的声明:
a += (a++) * (a++);
等同于以下任何一项:
a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)
在第一个a++
a
变为4之后,使用其中任何一个。所以你有3*4=12
(a
在第二个a++
之后变为5,但被丢弃,因为赋值a=
覆盖它)(a++)
是后增量,所以表达式的值是3
(a++)
是后增量,所以表达式的值现在是4
表达式求值是从左到右进行的
3 * 4 = 12
每次使用a++时,您都在后加a。这意味着第一个a++计算为3,第二个计算为4。3*4=12。如果下次使用a++时使用a++,它将递增1。那你干什么呢
a = 3 * (3 + 1) = 3 * 4 = 12
a++
表示“a的值,然后a加1”。所以当你跑步的时候
(a++) * (a++)
首先计算第一个a++
,并生成值3<代码>a然后递增1。然后计算第二个a++
a
生成4的值,然后再次递增(但现在这无关紧要)
所以这变成了
a = 3 * 4
它等于12。(a++)
表示返回a
和增量,所以
(a++)*(a++)
表示3*4是12。
表达式从左开始计算。它确实:
a = (3++) * (4++);
计算第一部分(3++)后,a为4,因此在下一部分中,a=3*4=12。
请注意,执行最后一个post增量(4++),但没有任何效果,因为在此之后为a分配了值12。前置和后置前缀增量的优先级高于乘法运算符。因此,表达式的计算结果为3*4。对运算符的工作原理普遍缺乏了解。老实说,每个操作符都是语法糖 你所要做的就是了解每个操作员背后的实际情况。假设如下:
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)
然后可以使用这些泛化重写复合运算符(为了简单起见,请忽略返回类型):
您可以重写您的示例:
int a = 3;
a = (a++) * (a++);
作为
可以使用多个变量进行拆分:
Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))
这样做肯定会更加冗长,但很明显,您永远不希望在一行上执行两个以上的操作
int a = 3;
a += (a++) * (a++);
首先构建语法树:
+=
a
*
a++
a++
要计算它,请从最外层的元素开始,然后递归下降。对于每个元素,请执行以下操作:
- 从左到右评估儿童
- 评估元素本身
+=
运算符很特殊:它被扩展为类似于left=left+right
,但只对表达式left
求值一次。但是,在右侧求值为值之前,左侧求值为值(而不仅仅是变量)
这导致:
+=
a
赋值的左侧a
计算为将在加法中使用的值3
*
a++
。这将返回3
的当前值,并将a
设置为4
a++
。这将返回4
的当前值,并将a
设置为5
+=
。在第三步中,左侧评估为3
,右侧评估为12
。因此,它将3+12=15分配给a
a
的最终值为15这里需要注意的一点是,运算符优先级对求值顺序没有直接影响。它只影响树的形式,从而间接影响顺序。但在树中的同级中,无论运算符优先级如何,求值总是从左到右。示例1
int a = 3;
a = (++a) * (a++);
System.out.println(a); // 16
示例2
int a = 3;
a = (++a) * (++a);
System.out.println(a); // 20
只需确保将根据位置更改值的++
表达式放在何处。以下是java代码:
int a = 3;
a = (a++)*(a++);
以下是字节码:
0 iconst_3
1 istore_1 [a]
2 iload_1 [a]
3 iinc 1 1 [a]
6 iload_1 [a]
7 iinc 1 1 [a]
10 imul
11 istore_1 [a]
发生的情况如下:
将3推入堆栈,然后从堆栈中弹出3并将其存储在a。
现在a=3,堆栈为空
0 iconst_3
1 istore_1 a
现在它将值从“a”(3)推送到堆栈中,然后增加a(3->4)
现在“a”等于“4”,堆栈等于{3}
然后再次加载“a”(4),推入堆栈并递增“a”
现在“a”等于5,堆栈等于{4,3}
因此,它最终从堆栈(4和3)中弹出第一个两个值,将其相乘并存储回堆栈(12)
现在“a”等于5,堆栈等于12
最后是堆栈中的pops 12,存储在a
11 istore_1 [a]
塔达 每个人都清楚地解释了第一个表达式,以及为什么a的值是12 对于下面的问题,答案对于不经意的观察者来说是显而易见的: 17在以下情况下:
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
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
因此,我们得到的输出为12。
在下列情况下:
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
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
这里要注意的要点是,在这种情况下,编译器是从左到右求解的,并且
对于增量后的情况,在计算中使用增量前的值,当我们从左向右移动时,使用增量值。任何人都不应该编写这样的代码。相信编译器——它比你更了解Java。我想是科雷
11 istore_1 [a]
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
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