有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

增量后为什么在这里忽略这个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

共 (6) 个答案

  1. # 1 楼答案

    后缀++增加变量的值,返回在增加之前的值。因此,示例中operator++的返回值将是1,当然1 + 2将给出3,然后将其分配给a。到赋值时,++已经将a的值增加到2(因为优先级),所以=覆盖增加的值

  2. # 2 楼答案

    这里不忽略运算符优先级

    关于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分配了两个值:

    • a++的计算过程中,2被分配给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++;
    

    我漏掉了其他几行,因为那里再也没有什么有趣的事情发生了

    作为一个有趣的旁注:显而易见,这段代码根本没有经过优化。原因是优化是Java世界中运行时环境(即JVM)的任务,而不是编译器的任务(例如^{

  3. # 3 楼答案

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

  4. # 4 楼答案

    postfix++操作符的意思是:

    在任何等式中使用变量的原始值,然后增加变量

  5. # 5 楼答案

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

  6. # 6 楼答案

    我对这个操作符优先级定义(定义为here)也有同样的问题,我认为上面的回答都不能准确地解释和澄清这个定义中的悖论。 这就是我认为后缀运算符比其他运算符(在本例中是二进制加号运算符)优先级更高的意思

    考虑下面的代码片段:

        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
    

    如您所见,java编译器会将具有两个可能求值的单个表达式z = x+++y;求值为z = x++ + y;。这意味着,从三个加号中,编译器假定前两个是后缀运算符,第三个是二进制加号运算符 这实际上是后缀运算符的优先级高于其他运算符的结果

    第二个代码片段通过将表达式写为z = x + ++y;来显示输出的差异,该表达式明确指定哪个加号是二进制运算符