Java: pre-,postfix operator precedences

前端 未结 5 653
-上瘾入骨i
-上瘾入骨i 2020-12-03 14:41

I have two similar questions about operator precedences in Java.

First one:

int X = 10;
System.out.println(X++ * ++X * X++); //it pr         


        
相关标签:
5条回答
  • 2020-12-03 15:05

    In short,

    Precedence is like preparing the expression to be calculated by putting parentheses. Evaluation comes next from left to right considering each pair of parentheses as a separate operation.

    For example,if i=2 then i+i++ becomes i+(i++) after precedence and evaluates to 2+2 = 4. However, i+++i becomes (i++)+i and evaluates to 2+3 = 5.

    Same to i+(i=5) which evaluates to 2+5 = 7.

    In fact the postfix operators do have higher precedence than prefix operators. For example, i+++++i becomes ((i++)++)+i after precedence which gives a compile error (the second postfix operator needs a variable to operate on but a value is found instead!). If both postfix and prefix operators had had equal precedence then the expression would have become (i++)+(++i) and evaluates to 2+4 = 6.

    If you need more explanation you can compile and run the following code and inspect the examples printed at the output.

    public class TestPrecedence {
        public static void main(String[] str) {
            int i = 0;
            System.out.println("\n");
            i = 2; System.out.println("i = " + i + "\n");
            i = 2; System.out.println("i++ = " + i++ + "\n");
            i = 2; System.out.println("++i = " + ++i + "\n");
            i = 2; System.out.println("i++i = (i++)i TestPrecedence.java:8: error: ')' expected\n"+
                                      "              i++i\n"+
                                      "                 ^\n");
            i = 2; System.out.println("i+-i = i+(-i) = " + (i+-i) + "\n");
            i = 2; System.out.println("++i++ = ++(i++) TestPrecedence.java:12: error: unexpected type\n"+
                                      "                ++i++ \n"+
                                      "                   ^\n"+
                                      "                required: variable\n"+
                                      "                found:    value\n");
            i = 2; System.out.println("i+++++i = ((i++)++)+i TestPrecedence.java:17: error: unexpected type\n"+
                                      "                      i+++++i\n"+
                                      "                       ^\n"+
                                      "                      required: variable\n"+
                                      "                      found:    value\n");
            i = 2; System.out.println("i++ + ++i = " + (i++ + ++i) + "\n");
            i = 2; System.out.println("i+(i=3) = " + (i+(i=3)) + " evaluates left to right\n");
            i = 2; System.out.println("i+i++ precedence yields i+(i++) evaluates to 2+2 = " + (i+i++) + "\n");
            i = 2; System.out.println("i+++i precedence yields (i++)+i evaluates to 2+3 = " + (i+++i) + "\n");
            System.out.println("\n");
        }
    }
    
    0 讨论(0)
  • 2020-12-03 15:07

    The reason why its 1440 is because

    1. x is set to 10 i.e 1st term is FIXED(overall equation 10 *)

    2. x is incremented by 1,x =11 now

    3. x is pre-incremented by 1 x=12 and second term FIXED now (overall equation 10 * 12 *)

    4. now x is set to 12 and third term FIXED(overall equation 10 * 12 *12)

    5. x is increment now but is in this case not used for evaluation,

    in short a term is FIXED when variable occurs which in this case is X

    2nd case: I'm not sure but I guess can be broken as,

    1. a=b+a
    2. a++

    which I think is what is happening.

    0 讨论(0)
  • 2020-12-03 15:07

    For the second one ->

    int a=1, b=2;             
    a += b + a++;
    

    Compiler will convert it to

     a = a + b + a++;
    

    Then apply your logic and you will find the reason why a is 4.

    0 讨论(0)
  • 2020-12-03 15:13

    The confusion stems from the fact that the operands are evaluated from left to right. This is done first, before any attention is paid to operator precedence/order of operations.

    This behavior is specified in JLS 15.7.2. Evaluate Operands before Operation

    So X++ * ++X * X++ is first evaluated as 10 * 12 * 12 which yields, as you saw, 1440.

    To convince yourself of this, consider the following:

    X = 10; System.out.println(X++ * ++X);
    X = 10; System.out.println(++X * X++);
    

    If X++ were done first, then ++X second, then multiplication, both should print the same number.

    But they do not:

    X = 10; System.out.println(X++ * ++X); // 120
    X = 10; System.out.println(++X * X++); // 121
    

    So how does this make sense? Well if we realize that operands are evaluated from left to right, then it makes perfect sense.

    X = 10; System.out.println(X++ * ++X); // 120 (10 * 12)
    X = 10; System.out.println(++X * X++); // 121 (11 * 11)
    

    The first line looks like

    X++       * ++X
    10 (X=11) * (X=12) 12
    10        * 12 = 120
    

    and the second

    ++X       * X++
    (X=11) 11 * 11 (X=12)
    11        * 11 = 121
    

    So why are prefix and postfix increment/decrement operators in the table?

    It is true that increment and decrement must be performed before multiplication. But what that is saying is that:

    Y = A * B++
    
    // Should be interpreted as
    Y = A * (B++)
    
    // and not
    Y = (A * B)++
    

    Just as

    Y = A + B * C
    
    // Should be interpreted as
    Y = A + (B * C)
    
    // and not
    Y = (A + B) * C
    

    It remains that the order of the evaluation of the operands occurs left-to-right.


    If you're still not conviced:

    Consider the following program:

    class Test
    {
        public static int a(){ System.out.println("a"); return 2; }
        public static int b(){ System.out.println("b"); return 3; }
        public static int c(){ System.out.println("c"); return 4; }
    
        public static void main(String[] args)
        {
            System.out.println(a() + b() * c());
            // Lets make it even more explicit
            System.out.println(a() + (b() * c()));
        }
    }
    

    If the arguments were evaluated at the time they were needed, either b or c would come first, the other next, and lastly a. However, the program outputs:

    a
    b
    c
    14
    a
    b
    c
    14
    

    Because, regardless of the order that they're needed and used in the equation, they're still evaluated left to right.

    Helpful reading:

    • What are the rules for evaluation order in Java?
    • a += a++ * a++ * a++ in Java. How does it get evaluated?
    • Appendix A: Operator Precedence in Java
    0 讨论(0)
  • 2020-12-03 15:17

    First step

    1) first postfix operator: X++ 
       1.a) X++ "replaced" by 10
       1.b) X incremented by one: 10+1=11
       At this step it should look like:  System.out.println(10 * ++X * X++), X = 11;
    
    2) prefix operator: ++X
       2.a) X "replaced" by 11
       2.b) X incremented by one: 11+1=12
       At this step it should look like:  System.out.println(10 * 12 * X++), X = 12;
    
    3) second POSTfix operator: X++
       3.a) X "replaced" by 12
       3.b) X incremented by one: 12+1=13
       At this step it should look like:  System.out.println(10 * 12 * 12),  X = 13;
    

    This prints 10 * 12 * 12 = 1440

    This is the bytecode for the first step

     1. bipush 10
     2. istore_0
     3. getstatic java/lang/System/out Ljava/io/PrintStream;
     4. iload_0
     5. iinc 0 1
     6. iinc 0 1
     7. iload_0
     8. imul
     9. iload_0
    10. iinc 0 1
    11. imul
    12. invokevirtual java/io/PrintStream/println(I)V
    13. return
    

    This do the following:

     1. Push 10 to the stack
     2. Pop 10 from the stack to X variable
     3. Push X variable value (10) to the stack
     5. Increment local variable X (11)
     6. Increment local variable X (12)
     7. Push X variable value (12) to the stack
     8. Multiply top and subtop (10*12) Now Top = 120 
     9. Push X variable value (12) to the stack
    10. Increment local variable X (13)
    11. Multiply top and subtop (120*12) Now Top = 1440
    

    Notice than the last increment (10.) is done after the push of X to the stack

    0 讨论(0)
提交回复
热议问题