为什么这里忽略 Java 运算符优先级?

发布于 2024-08-06 23:18:07 字数 935 浏览 9 评论 0原文

以下代码打印出“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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

很酷又爱笑 2024-08-13 23:18:07

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 of operator++ in your example will be 1, and of course 1 + 2 will give 3, which is then assigned to a. By the time of assignment, ++ has already incremented the value of a to 2 (because of precedence), so = overwrites that incremented value.

世界和平 2024-08-13 23:18:07

这里不会忽略运算符优先级。

关于 a++ 唯一有点令人困惑的是,后缀 ++ 运算符有两个不同的效果:

  1. 它将所应用的变量增加 1,
  2. 它的返回值等于到变量之前的值增加

所以如果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++ 求值期间被分配给 a
  • 3 作为分配结果被分配给 a

因为第二次分配发生在第一次分配之后第一个,您只能看到第二个的效果,并且您将始终观察到该行之后的 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 (a.k.a "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 (a.k.a "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-3 行简单地实现

int a=1, b=2;

第 4-10 行实现

a = b + a++;

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:

  1. it increases the variable it's applied to by one
  2. it has a return value that is equal to the value of the variable before it is increased

So if a has the 1 and b has the value 2 before this line:

a = b + a++;

Then the following steps happen:

  • evaluate b
    • the expression b has the value 2, so remember the value 2
  • evaluate a++
    • the expression a++ has the value 1, so remember the value 1
    • increment the value in variable a by one, so it now holds the value 2
  • add the results of the two expressions (which are 2 and 1 respectively)
  • 2 + 1 = 3
  • assign 3 to the variable a

As you see, the code effectively assigns two values to a:

  • 2 is assigned to a during the evaluation of a++
  • 3 is assigned to a as a result of the assignment

Since 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):

   // 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 (a.k.a "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 (a.k.a "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

Lines 0-3 simply implement

int a=1, b=2;

The lines 4-10 implement

a = b + a++;

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).

缪败 2024-08-13 23:18:07

后自增/自减运算符 (a++) 返回自增之前的值。预增/预减 (++a) 返回增量后的值。

The postincrement/decrement operator (a++) returns the value before the increment. The preincrement/decrement (++a) returns the value after the increment.

灵芸 2024-08-13 23:18:07

我对这个运算符优先级定义也有同样的问题(如此处定义的)我认为上述答复都没有准确解释和澄清这个定义中的悖论。
这就是我认为后缀运算符相对于其他运算符(在本例中为二元加运算符)的更高优先级的含义。

考虑以下代码片段:

    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; 来显示输出的不同之处。 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:

    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

As you can see, a single expression z = x+++y; which has two possible evaluations, will be evaluated as z = 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.

み零 2024-08-13 23:18:07

这不是优先级问题,而是运算符的定义问题。 根据定义后缀运算符在封闭表达式中使用变量后执行。

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.

伤痕我心 2024-08-13 23:18:07

后缀 ++ 运算符的意思是:

在任何方程中使用变量的原始值,然后递增变量。

what the postfix ++ operator is saying is:

Use the original value of the variable in whatever equation, and then increment the variable afterwards.

帅的被狗咬 2024-08-13 23:18:07

我从未见过

 a = b + a++; 

被使用过,它让我觉得编码很糟糕。像这样使用它我认为也意味着你可以写:

int a++ = 1;

这是行不通的。

通常你会看到

int a = 1;
int b = 2;
a = b + a; // 3

a = 1;
a++;
a = b + a; // 4

I have never seen

 a = b + a++; 

being used, it strikes me as bad coding. Using it like that would i think also mean that you could write:

int a++ = 1;

which doesn't work.

normally you would see

int a = 1;
int b = 2;
a = b + a; // 3

a = 1;
a++;
a = b + a; // 4
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文