为什么在此忽略此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."":()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
Postfix ++
增加变量的值,并返回增量前的值 。 因此,示例中operator++
的返回值将为1
,当然1 + 2
将给出3
,然后将其分配给a
。 到分配时, ++
已经将a
的值增加到2
(因为优先级),所以=
覆盖递增的值。
此处不会忽略运算符优先级。
关于a++
的唯一有点混乱的事情是postfix ++
运算符有两个不同的效果:
- 它增加了它应用的变量
- 它的返回值等于变量增加前的值
因此,如果a
具有1且b
在此行之前具有值2:
a = b + a++;
然后执行以下步骤:
- 评估
b
- 表达式
b
的值为2,所以请记住值2
- 表达式
- 评估
a++
- 表达式
a++
的值为1,所以请记住值1 - 将变量
a
的值递增1,因此它现在保持值2
- 表达式
- 添加两个表达式的结果(分别为2和1)
- 2 + 1 = 3
- 将3分配给变量
a
如您所见,代码有效地将两个值分配给:
- 在评估
a++
期间,将2分配给a
- 作为分配的结果,将3分配给
a
由于第二个赋值发生在第一个赋值之后,因此您只能看到第二个赋值的效果,并且您将始终在该行之后观察到值为3。
编辑:我将尝试提供反编译代码的解释。 它可能有点难以理解,除非您知道JVM如何在内部工作(即您知道JVM是如何基于堆栈的VM以及这意味着什么):
// Push the constant 1 on the stack 0: iconst_1 // Pop the topmost value from the stack (1) and store it in the local variable #1 (aka "a") 1: istore_1 // Push the constant 2 on the stack 2: iconst_2 // Pop the topmost value from the stack (2) and store it in the local variable #2 (aka "b") 3: istore_2 // Load the local variable #2 ("b") and push its value (2) on the stack 4: iload_2 // Load the local variable #1 ("a") and push its value (1) on the stack 5: iload_1 // Increment the local variable #1 by 1 (this action does not use the stack!) 6: iinc 1, 1 // Pop the 2 topmost values from the stack (2 and 1), add them and push the result (3) back on the stack 9: iadd // Pop the topmost value from the stack (3) and store it in local variable #1 ("a") 10: istore_1
第0-4行简单地实现
int a=1, b=2;
第4-10行实现
a = b + a++;
我已经遗漏了其他线路,因为那里没有任何有趣的事情发生了。
作为一个有趣的旁注:很明显,这段代码根本没有优化。 原因是优化是Java世界中运行时环境(即JVM)的任务,而不是编译器(例如javac
)的任务。
postincrement / decrement运算符(a ++)返回增量前的值。 preincrement / decrement(++ a)返回增量后的值。
我对此运算符优先级定义(如此处定义)有同样的问题,我认为上述回复都没有完全解释和澄清此定义中的悖论。 这就是我认为postfix运算符优先于其他运算符(在本例中为binary plus运算符)的含义。
请考虑以下代码片段:
int x = 1, y =4 , z; z = x+++y; // evaluates as: x++ + y System.out.println("z : " + z); // z: 5 System.out.println("y : " + y); // y: 4 System.out.println("x : " + x); // x: 2 x = 1; y =4 ; z = x + ++y; System.out.println("z : " + z); // z: 6 System.out.println("y : " + y); // y: 5 System.out.println("x : " + x); // x: 1
如您所见,单个表达式z = x+++y;
有两种可能的评估,将被评估为z = x++ + y;
通过java编译器。 这意味着从三个加号组合在一起,编译器将前两个作为后缀运算符,第三个作为二进制加运算符。 事实上,这是后缀运算符优先于其他运算符的结果。
第二个代码片段通过将表达式写为z = x + ++y;
显示输出如何不同z = x + ++y;
其中明确指定哪个加号是二元运算符。
这不是优先事项,而是运营商定义的问题。 根据定义 ,后缀运算符在封闭表达式中使用变量后执行。
postfix ++运算符所说的是:
在任何等式中使用变量的原始值,然后增加变量。
我从来没见过
a = b + a++;
正在被使用,它让我感觉不好编码。 像我那样使用它也意味着你可以写:
int a++ = 1;
这不起作用。
通常你会看到
int a = 1; int b = 2; a = b + a; // 3 a = 1; a++; a = b + a; // 4