I have two similar questions about operator precedences in Java.
First one:
int X = 10;
System.out.println(X++ * ++X * X++); //it pr
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");
}
}
The reason why its 1440 is because
x is set to 10 i.e 1st term is FIXED(overall equation 10 *)
x is incremented by 1,x =11 now
x is pre-incremented by 1 x=12 and second term FIXED now (overall equation 10 * 12 *)
now x is set to 12 and third term FIXED(overall equation 10 * 12 *12)
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,
a=b+a
a++
which I think is what is happening.
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.
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
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.
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:
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