问题
According to http://introcs.cs.princeton.edu/java/11precedence/, post-increment operator has higher precedence than addition operator.
So, for the following code:
int i = 1;
int j = i + i++;
System.out.println(j);
I would have thought that the expression assigned to j would have been evaluated as follows (with each line being a "step" in the evaluation) :
i + i++
i + (1) // do post-increment operator; returns 1, and makes i = 2
(2) + (1) // do addition operator. need to get the operand i, so do that.
3
But when I try this program, the value of j is 2.
So I'm confused. In the expression, does it replace all the "i"s in the expression with the current value of i, BEFORE even touching the i++ ?
Edit: the phrase "evaluation order" that people here used, helped me to find the following potentially helpful stackoverflow answer: What are the rules for evaluation order in Java? .
Edit: I made my best guess into an answer below. I still welcome corrections to it.
回答1:
According to Java Language Specification, 15.7.1
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
Hence the i
on the left side of the addition operator is evaluated before i++
on the right side.
回答2:
Post Increment - First uses previous variable value and then increments.
Pre increment - First increments and then uses new variable value.
int i = 1;
int j = i + i++;
System.out.println(j);// 2
System.out.println(i);// 2
Here first i is substituted with previous i value i,e 1 +
again old value of i, so j will become 2, and then i is incremented to 2.
Now consider this code
int i = 1;
int j = i++ + ++i;
System.out.println(j);// 4
System.out.println(i);// 3
Here first i is incremented (pre), so i becomes 2 then i is substituted i,e j = 2 + 2, now j value will be 4 and again i is incremented (post) by one so i's current value will be 3.
回答3:
Do not let yourself being mislead by the "precedence" word. What the tutorial is stating is that the post-increment operator binds stronger than the addition, as regards parsing expression.
If we made explicit the parentheses, the expression in your example would appear (i + (i++))
, not ((i + i)++)
.
That's what precedence means: without explicit parentheses, put them implicitly around the post-increment before, then around the addition.
When the components of the expression have been successfully grouped, evaluation rules are considered. In this case, as Korolar pointed out, JLS 15.7.1 is the paragraph to be considered, which (in simple words) dictates left-to-right evaluation of the addition operation.
回答4:
Edit: I do not understand the answers others have given completely, but this is my best guess at what is happening. If someone wants to correct this guess, please do so.
My best guess:
a + b * c
, where a, b, and c are variables, is made into an expression tree, where the operator with lowest precedence is at the top of the tree:
+
/ \
a *
/ \
b c
Now, this tree is evaluated like so: the + operator gets evaluated. To do so, it (recursively) evaluates the left subtree, and its right subtree, then adds these values.
In full, this is what happens:
- addition operator gets evaluated.
it says "evaluate my left subtree, then my right subtree,
then add them together. i return that value"
- left subtree: is a. evaluate variable a into a value.
(that is, get the value of variable a.)
- right subtree: i'm a multiplication operator. to evaluate me,
evaluate my left subtree, then my right subtree, the nmultiply
them togeter. i return that value.
- left subtree: is variable b. evalute that.
- right subtree: is variable c. evaluate that.
This is why it a
finishes its evaluation first, then b
, then c
, then b * c
, then a + (b * c)
In expressions with ++i stuff, the same thing happens. For example, with ++i + i++
, the expression tree would look like this:
+
/ \
preinc postinc
| |
i i
where (for example) preinc means the preincrement operator (and preincrement operator takes exactly one operand: a variable). the difference here is that when the subtree that has preinc as its root needs to get evaluated, to "evaluate the preinc operator tree" doesn't mean "replace the variable in the operand with the value of the variable" (the way it would for, say, 2 + i ), but instead it means "increment the value in variable i, and then the value of preinc(i) is the new value in the variable i".
in a similar way, the assignment operator = works a little differently than, say, 2 + i.
int j;
j = 3;
the expression tree here is
=
/ \
j 3
and when a tree with assignment operator as its root needs to get evaluated, this means "the left hand operator must be a variable -- not a value! and then evaluate the right subtree (we expect it to evaluate it to a value), and then put the value in the right subtree in the variable in the left subtree. Now, the value returned by =(j, 3) is the value in the right subtree".
with this guess, I'm able to correctly come up with the answers given for examples in the Java Language Specification on Evaluation Order (link is: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7).
that is, if i draw the expression tree, the following two examples are solvable by me:
example:
int i = 2;
int j = (i = 3) * i;
System.out.println(j);
example:
int b = 9;
b = b + (b = 3);
System.out.println(b);
来源:https://stackoverflow.com/questions/39925647/when-are-values-in-java-variables-evaluated-returned-fetched-in-an-expression