为什么这里忽略 Java 运算符优先级?
以下代码打印出“3”,而不是您所期望的“4”。
public class Foo2 {
public static void main(String[] args) {
int a=1, b=2;
a = b + a++;
System.out.println(a);
}
}
我明白了。后缀增量发生在加载“a”的值之后。 (见下文)。
我不太明白的是为什么。 postfix ++ 的运算符优先级高于 + 那么它不应该先执行吗?
% javap -c Foo2
Compiled from "Foo2.java"
public class Foo2 extends java.lang.Object{
public Foo2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_2
5: iload_1
6: iinc 1, 1
9: iadd
10: istore_1
11: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
14: iload_1
15: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
18: return
The following code prints out "3", not "4" as you might expect.
public class Foo2 {
public static void main(String[] args) {
int a=1, b=2;
a = b + a++;
System.out.println(a);
}
}
I understand how. The postfix increment happens after the value of "a" has been loaded. (See below).
What I don't quite understand is the why. The operator precedence of postfix ++ is higher than + so shouldn't it execute first?
% javap -c Foo2
Compiled from "Foo2.java"
public class Foo2 extends java.lang.Object{
public Foo2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_2
5: iload_1
6: iinc 1, 1
9: iadd
10: istore_1
11: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
14: iload_1
15: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
18: return
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
Postfix
++
递增变量的值,并返回递增之前的值。因此,示例中operator++
的返回值为1
,当然1 + 2
会给出3
>,然后将其分配给a
。在赋值时,++
已将a
的值增加到2
(因为优先级),因此=< /code> 覆盖该增加的值。
Postfix
++
increments the value of variable, and returns the value that was there before the increment. Thus, the return value ofoperator++
in your example will be1
, and of course1 + 2
will give3
, which is then assigned toa
. By the time of assignment,++
has already incremented the value ofa
to2
(because of precedence), so=
overwrites that incremented value.这里不会忽略运算符优先级。
关于
a++
唯一有点令人困惑的是,后缀++
运算符有两个不同的效果:所以如果
a
在这一行之前有1并且b
有值2:那么以下步骤发生:
b
b
的值为2,所以记住值2a++
a++
的值为 1,因此请记住值 1a
中的值增加 1,因此它现在的值为 2a
如您所见,代码有效地将两个值赋给
a
:a++
求值期间被分配给a
a
因为第二次分配发生在第一次分配之后第一个,您只能看到第二个的效果,并且您将始终观察到该行之后的
a
值为 3。编辑:我将尝试提供反编译代码的解释。除非您知道 JVM 内部如何工作(即您知道 JVM 是基于堆栈的 VM 以及这意味着什么),否则可能有点难以理解:
第 0-3 行简单地实现
第 4-10 行实现
I省略了其他行,因为那里不再发生任何有趣的事情。
作为一个有趣的旁注:很明显,这段代码根本没有优化。原因是优化是 Java 世界中运行时环境(即 JVM)的任务,而不是编译器(例如
javac
)的任务。Operator precedence is not being ignored here.
The only slightly confusing thing about
a++
is that the postfix++
operator has two distinct effects:So if
a
has the 1 andb
has the value 2 before this line:Then the following steps happen:
b
b
has the value 2, so remember the value 2a++
a++
has the value 1, so remember the value 1a
by one, so it now holds the value 2a
As you see, the code effectively assigns two values to
a
:a
during the evaluation ofa++
a
as a result of the assignmentSince the second assignment happens after the first one, you only see the effect of the second one and you will always observe
a
as having the value 3 after that line.Edit: I'll try to provide an interpretation of the decompiled code. It might be a bit hard to follow, unless you know how the JVM works internally (i.e. you know how that the JVM is a stack-based VM and what that means):
Lines 0-3 simply implement
The lines 4-10 implement
I've left out the other lines, as nothing interesting happens there anymore.
As an interesting sidenote: it's plainly visible that this code is not optimized at all. The reason for this is that optimization is the task of the runtime environment (i.e. the JVM) in the Java world and not of the compiler (
javac
for example).后自增/自减运算符 (a++) 返回自增之前的值。预增/预减 (++a) 返回增量后的值。
The postincrement/decrement operator (a++) returns the value before the increment. The preincrement/decrement (++a) returns the value after the increment.
我对这个运算符优先级定义也有同样的问题(如此处定义的)我认为上述答复都没有准确解释和澄清这个定义中的悖论。
这就是我认为后缀运算符相对于其他运算符(在本例中为二元加运算符)的更高优先级的含义。
考虑以下代码片段:
如您所见,具有两个可能计算值的单个表达式
z = x+++y;
将被计算为z = x++ + y;
代码>由java编译器。这意味着,对于组合在一起的三个加号,编译器假定前两个加号为后缀运算符,第三个加号为二元加运算符。 这实际上是后缀运算符比其他运算符具有更高优先级的结果。第二个代码片段通过将表达式编写为
z = x + ++y; 来显示输出的不同之处。 code> 明确指定哪个加号是二元运算符。
I had the same problem with this operator precedence definition (as defined here) and I think none of the above replies are exactly explaining and clarifying the paradox in this definition.
This is what I think the higher precedence of postfix operator to other operators (in this example to binary plus operator) means.
Consider the following code fragments:
As you can see, a single expression
z = x+++y;
which has two possible evaluations, will be evaluated asz = x++ + y;
by java compiler. This means that from three plus sign which came together, compiler assumes the first two of them as a postfix operator and the third one as a binary plus operator. This is in fact a result of higher precedence of postfix operator over other operators.The second code fragment shows how the outputs differ by writing the expression as
z = x + ++y;
which explicitly specifies which plus sign is a binary operator.这不是优先级问题,而是运算符的定义问题。 根据定义后缀运算符在封闭表达式中使用变量后执行。
This isn't a matter of precedence, it's a matter of the definition of the operator. By definition the postfix operator executes after the variable is used in the enclosing expression.
后缀 ++ 运算符的意思是:
在任何方程中使用变量的原始值,然后递增变量。
what the postfix ++ operator is saying is:
Use the original value of the variable in whatever equation, and then increment the variable afterwards.
我从未见过
被使用过,它让我觉得编码很糟糕。像这样使用它我认为也意味着你可以写:
这是行不通的。
通常你会看到
I have never seen
being used, it strikes me as bad coding. Using it like that would i think also mean that you could write:
which doesn't work.
normally you would see