x == (x = y)가 (x = y) == x와 다른 이유는 무엇입니까?
다음 예제를 고려하십시오.
class Quirky {
public static void main(String[] args) {
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
x = 1; // reset
System.out.println((x = y) == x); // true
}
}
Java 언어 사양에 오른쪽과 비교하기 위해 변수의 이전 값을로드하는 항목이 있는지 확실하지 않습니다 ( x = y
), 대괄호로 암시 된 순서로 먼저 계산해야합니다.
왜 첫 번째 표현식은로 평가 않습니다 false
,하지만 두 번째로 평가 true
? 나는 (x = y)
먼저 평가 될 것으로 예상 했을 때, x
그 자체와 비교 3
하고 return 할 true
것이다.
이 질문은 Java 표현식 에서 하위 표현식의 평가 순서와 다르며 x
여기서는 분명히 '서브 표현식'이 아닙니다. '평가'하기보다는 비교 를 위해 로드 되어야합니다. 문제는 자바 별과 표현이다 x == (x = y)
일반적으로 까다로운 면접 질문 제작 된 억지 실용적 구조와는 달리, 실제 프로젝트에서왔다. 비교 및 교체 관용구를 한 줄로 대체해야했습니다.
int oldX = x;
x = y;
return oldX == y;
이는 x86 CMPXCHG 명령보다 훨씬 간단하여 Java에서 더 짧은 표현식을 받아야합니다.
대괄호로 암시 된 순서대로 먼저 계산해야합니다.
괄호는 계산 또는 평가 순서에 (일반적인) 영향을 미친다는 일반적인 오해입니다. 그들은 표현의 일부를 특정 트리로 강제 변환하여 올바른 피연산자를 작업에 대한 올바른 연산에 바인딩합니다.
(그리고이를 사용하지 않으면이 정보는 연산자의 "우선 순위"와 연관성에서 비롯됩니다. 이는 언어의 구문 트리가 정의 된 방식의 결과입니다. 괄호를 사용하지만 우선 순위 규칙에 의존하지 않는다고 단순화합니다.)
일단 완료되면 (즉, 코드가 프로그램으로 파싱되면) 해당 피연산자는 여전히 평가해야하며 수행 방법에 대한 별도의 규칙이 있습니다. Java에서 먼저 평가됩니다.
모든 언어에 해당되는 것은 아닙니다. 예를 들어, C ++에서 &&
or 와 같은 단락 연산자를 사용하지 않는 한 ||
피연산자의 평가 순서는 일반적으로 지정되어 있지 않으며 어떤 식 으로든 의존해서는 안됩니다.
교사는 "이렇게하면 추가가 먼저 이루어집니다"와 같은 잘못된 문구를 사용하여 운영자 우선 순위 설명을 중단해야합니다. 식을 감안할 때 x * y + z
적절한 설명은 "연산자 우선 순위는 또한 사이에 발생하게 될 것 x * y
와 z
오히려 사이보다, y
그리고 z
어떤"순서 "의 언급은 없다".
==
이진 항등 연산자 입니다.
이항 연산자 의 왼쪽 피연산자 는 오른쪽 피연산자의 일부가 평가 되기 전에 완전히 평가 된 것으로 보입니다 .
LouisWasserman이 말했듯이 표현은 왼쪽에서 오른쪽으로 평가됩니다. 그리고 자바는 "평가"가 실제로하는 일에 신경 쓰지 않으며, (비 휘발성, 최종) 값을 생성하는 것에 만 관심이있다.
//the example values
x = 1;
y = 3;
의 첫 번째 출력을 계산하기 System.out.println()
위해 다음이 수행됩니다.
x == (x = y)
1 == (x = y)
1 == (x = 3) //assign 3 to x, returns 3
1 == 3
false
두 번째를 계산하려면
(x = y) == x
(x = 3) == x //assign 3 to x, returns 3
3 == x
3 == 3
true
두 번째 값은 항상의 초기 값에 관계없이, true로 평가되므로주의 x
하고 y
, 효과적으로이 할당 된 변수에 값 할당을 비교하기 때문에, 그리고 a = b
하고 b
, 그 순서대로 평가됩니다 항상 동일 정의에 의해.
Java 언어 사양에 변수의 이전 값을로드하도록 지시하는 항목이 있는지 확실하지 않습니다 ...
There is. Next time you are unclear what the specification says, please read the specification and then ask the question if it is unclear.
... the right side
(x = y)
which, by the order implied by brackets, should be calculated first.
That statement is false. Parentheses do not imply an order of evaluation. In Java, the order of evaluation is left to right, regardless of parentheses. Parentheses determine where the subexpression boundaries are, not the order of evaluation.
Why does the first expression evaluate to false, but the second evaluate to true?
The rule for the ==
operator is: evaluate the left side to produce a value, evaluate the right side to produce a value, compare the values, the comparison is the value of the expression.
In other words, the meaning of expr1 == expr2
is always the same as though you had written temp1 = expr1; temp2 = expr2;
and then evaluated temp1 == temp2
.
The rule for the =
operator with a local variable on the left side is: evaluate the left side to produce a variable, evaluate the right side to produce a value, perform the assignment, the result is the value that was assigned.
So put it together:
x == (x = y)
We have a comparison operator. Evaluate the left side to produce a value -- we get the current value of x
. Evaluate the right side: that's an assignment so we evaluate the left side to produce a variable -- the variable x
-- we evaluate the right side -- the current value of y
-- assign it to x
, and the result is the assigned value. We then compare the original value of x
to the value that was assigned.
You can do (x = y) == x
as an exercise. Again, remember, all the rules for evaluating the left side happen before all the rules of evaluating the right side.
I would have expected (x = y) to be evaluated first, and then it would compare x with itself (3) and return true.
Your expectation is based on a set of incorrect beliefs about the rules of Java. Hopefully you now have correct beliefs and will in the future expect true things.
This question is different from "order of evaluation of subexpressions in a Java expression"
This statement is false. That question is totally germane.
x is definitely not a 'subexpression' here.
This statement is also false. It is a subexpression twice in each example.
It needs to be loaded for the comparison rather than to be 'evaluated'.
I have no idea what this means.
Apparently you still have many false beliefs. My advice is that you read the specification until your false beliefs are replaced by true beliefs.
The question is Java-specific and the expression x == (x = y), unlike far-fetched impractical constructs commonly crafted for tricky interview questions, came from a real project.
The provenance of the expression is not relevant to the question. The rules for such expressions are clearly described in the specification; read it!
It was supposed to be a one-line replacement for the compare-and-replace idiom
Since that one-line replacement caused a great deal of confusion in you, the reader of the code, I would suggest that it was a poor choice. Making the code more concise but harder to understand is not a win. It is unlikely to make the code faster.
Incidentally, C# has compare and replace as a library method, which can be jitted down to a machine instruction. I believe Java does not have such a method, as it cannot be represented in the Java type system.
It is related to operator precedence and how operators are getting evaluated.
Parentheses '()' has higher precedence and has associativity left to right. Equality '==' come next in this question and has associativity left to right. Assignment '=' come last and has associativity right to left.
System use stack to evaluate expression. Expression gets evaluated left to right.
Now comes to original question:
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
First x(1) will be pushed to stack. then inner (x = y) will be evaluated and pushed to stack with value x(3). Now x(1) will be compared against x(3) so result is false.
x = 1; // reset
System.out.println((x = y) == x); // true
Here, (x = y) will be evaluated, now x value become 3 and x(3) will be pushed to stack. Now x(3) with changed value after equality will be pushed to stack. Now expression will be evaluated and both will be same so result is true.
It is not the same. The left hand side will always be evaluated before the right hand side, and the brackets don't specify an order of execution, but a grouping of commands.
With:
x == (x = y)
You are basically doing the same as:
x == y
And x will have the value of y after the comparison.
While with:
(x = y) == x
You are basically doing the same as:
x == x
After x took y's value. And it will always return true.
In the first test you're checking does 1 == 3.
In the second test your checking does 3 == 3.
(x = y) assigns the value and that value is tested. In the former example x = 1 first then x is assigned 3. Does 1 == 3?
In the latter, x is assigned 3, and obviously it's still 3. Does 3 == 3?
Consider this other, maybe simpler example:
int x = 1;
System.out.println(x == ++x); // false
x = 1; // reset
System.out.println(++x == x); // true
Here, the pre-increment operator in ++x
must be applied before the comparison is made — just like (x = y)
in your example must be calculated before the comparison.
However, expression evaluation still happens left → to → right, so the first comparison is actually 1 == 2
while the second is 2 == 2
.
The same thing happens in your example.
Expressions are evaluated from left to right. In this case:
int x = 1;
int y = 3;
x == (x = y)) // false
x == t
- left x = 1
- let t = (x = y) => x = 3
- x == (x = y)
x == t
1 == 3 //false
(x = y) == x); // true
t == x
- left (x = y) => x = 3
t = 3
- (x = y) == x
- t == x
- 3 == 3 //true
Basically the first statement x had it's value 1 So Java compares 1 == to new x variable which won't be the same
In the second one you said x=y which means the value of x changed and so when you call it again it'll be the same value hence why it's true and x ==x
== is a comparison equality operator and it works from left to right.
x == (x = y);
here the old assigned value of x is compared with new assign value of x, (1==3)//false
(x = y) == x;
Whereas, here new assign value of x is compared with the new holding value of x assigned to it just before comparison, (3==3)//true
Now consider this
System.out.println((8 + (5 * 6)) * 9);
System.out.println(8 + (5 * 6) * 9);
System.out.println((8 + 5) * 6 * 9);
System.out.println((8 + (5) * 6) * 9);
System.out.println(8 + 5 * 6 * 9);
Output:
342
278
702
342
278
Thus, Parentheses plays its major role in arithmetic expressions only not in comparison expressions.
The thing here is the arithmatic operators/relational operators precedency order out of the two operators =
vs ==
the dominant one is ==
(Relational Operators dominates ) as it precedes =
assignment operators. Despite precedence, the order of evaluation is LTR (LEFT TO RIGHT) precedence comes into picture after evaluation order. So, Irrespective of any constraints evaluation is LTR.
It is easy in the second comparison on the left is assignment after assigning y to x (on the left) you then comparing 3 == 3. In the first example you are comparing x = 1 with new assign x = 3. It seems that there is always taken current state reading statements from left to right of x.
The kind of question you asked is a very good question if you want to write a Java compiler, or test programs to verify that a Java compiler is working correctly. In Java, these two expressions must produce the results that you saw. In C++, for example, they don't have to - so if someone reused parts of a C++ compiler in their Java compiler, you might theoretically find that the compiler doesn't behave as it should.
As a software developer, writing code that is readable, understandable and maintainable, both versions of your code would be considered awful. To understand what the code does, one has to know exactly how the Java language is defined. Someone who writes both Java and C++ code would shudder looking at the code. If you have to ask why a single line of code does what it does, then you should avoid that code. (I suppose and hope that the guys who answered your "why" question correctly will themselves avoid that ind of code as well).
참고URL : https://stackoverflow.com/questions/53749841/why-is-x-x-y-not-the-same-as-x-y-x
'Programing' 카테고리의 다른 글
web.config 파일을 사용하여 HTTPS를 강제 실행하는 방법 (0) | 2020.05.06 |
---|---|
git difftool 및 mergetool로 Meld 설정 및 사용 (0) | 2020.05.06 |
Bash에서 공백을 마침표로 교체 (0) | 2020.05.06 |
Java 클래스가 빈 줄과 다르게 컴파일되는 이유는 무엇입니까? (0) | 2020.05.06 |
Objective-C에서 어떤 클래스의 객체를 테스트합니까? (0) | 2020.05.05 |