[java] 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)까다로운 인터뷰 질문을 위해 제작 된 비현실적인 구성과 달리 실제 프로젝트에서 나온 표현이 Java에 고유합니다 . 비교 및 교체 관용구를 한 줄로 대체해야했습니다.

int oldX = x;
x = y;
return oldX == y;

이는 x86 CMPXCHG 명령보다 훨씬 간단하여 Java에서 더 짧은 표현식을 받아야합니다.



답변

대괄호로 암시 된 순서대로 먼저 계산해야합니다.

괄호는 계산 또는 평가 순서에 (일반적인) 영향을 미친다는 일반적인 오해입니다. 그들은 표현의 일부를 특정 트리로 강제 변환하여 올바른 피연산자를 작업에 대한 올바른 연산에 바인딩합니다.

(그리고이를 사용하지 않으면이 정보는 연산자의 “우선 순위”와 연관성에서 비롯됩니다. 이는 언어의 구문 트리가 정의 된 방식의 결과입니다. 사실, 여전히 여전히 괄호를 사용하지만 우선 순위 규칙에 의존하지 않는다고 단순화합니다.)

일단 완료되면 (즉, 코드가 프로그램으로 파싱되면) 해당 피연산자는 여전히 평가해야하며 그 수행 방법에 대한 별도의 규칙이 있습니다. 상기 규칙 (Andrew가 우리에게 보여 주었 듯이)은 각 작업의 LHS를 나타냅니다 Java에서 먼저 평가됩니다.

모든 언어에 해당되는 것은 아닙니다. 예를 들어, C ++에서 &&or 와 같은 단락 연산자를 사용하지 않는 한 ||피연산자의 평가 순서는 일반적으로 지정되어 있지 않으며 어떤 식 으로든 의존해서는 안됩니다.

교사는 “이렇게하면 추가가 먼저 이루어집니다”와 같은 잘못된 문구를 사용하여 운영자 우선 순위 설명을 중단해야합니다. 식을 감안할 때 x * y + z적절한 설명은 “연산자 우선 순위는 또한 사이에 발생하게 될 것 x * yz오히려 사이보다, y그리고 z어떤”순서 “의 언급은 없다”.


답변

==이진 항등 연산자 입니다.

이항 연산자 의 왼쪽 피연산자오른쪽 피연산자의 일부가 평가 되기 전에 완전히 평가 된 것으로 보입니다 .

Java 11 사양> 평가 순서> 먼저 왼쪽 피연산자 평가


답변

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 언어 사양에 변수의 이전 값을로드하도록 지시하는 항목이 있는지 확실하지 않습니다 …

있습니다. 당신이 사양의 말씀 불분명 다음 번에, 사양을 읽어 주시기 바랍니다 다음 이 명확하지 않은 경우 질문.

… 오른쪽 (x = y)대괄호로 암시 된 순서로 먼저 계산해야합니다.

그 진술은 거짓이다. 괄호는 평가 순서를 의미하지 않습니다 . Java에서 괄호에 관계없이 평가 순서는 왼쪽에서 오른쪽입니다. 괄호는 하위 식 경계가 평가 순서가 아닌 위치를 결정합니다.

첫 번째 표현은 왜 거짓으로 평가되고 두 ​​번째 표현은 참으로 평가됩니까?

에 대한 규칙 ==연산자 은 다음과 같습니다. 왼쪽을 평가하여 값을 생성하고, 오른쪽을 평가하여 값을 생성하고 값을 비교하면 비교는 표현식의 값입니다.

다시 말해, 의미 expr1 == expr2는 항상 작성 temp1 = expr1; temp2 = expr2;하고 평가 한 것과 동일 temp1 == temp2합니다.

=왼쪽에 로컬 변수가 있는 연산자 의 규칙은 다음 과 같습니다. 왼쪽을 평가하여 변수를 생성하고, 오른쪽을 평가하여 값을 생성하고, 할당을 수행하며, 결과는 지정된 값입니다.

함께 정리 해보자.

x == (x = y)

비교 연산자가 있습니다. 왼쪽을 평가하여 값을 x만듭니다. 현재 값은 입니다. 우변을 평가하십시오 : 그것은 할당입니다 그래서 우리는 변수를 생성하기 위해 좌변을 평가합니다-변수 x-우변을 평가합니다-의 현재 값 y-에 할당 x하고 결과는 할당 된 값입니다. 그런 다음 원래 값을 비교합니다x 할당 된 .

당신은 (x = y) == x운동으로 할 수 있습니다 . 다시 한 번, 왼쪽을 평가하는 모든 규칙은 오른쪽을 평가하는 모든 규칙보다 먼저 발생한다는 것을 기억하십시오 .

(x = y)를 먼저 평가 한 다음 x를 자체와 비교하고 (3) true를 반환합니다.

Java 규칙에 대한 잘못된 믿음을 기반으로합니다. 바라건대 이제는 올바른 믿음을 가지고 있으며 앞으로는 참된 일을 기대할 것입니다.

이 질문은 “Java 표현식에서 하위 표현식의 평가 순서”와 다릅니다

이 진술은 거짓이다. 그 질문은 완전히 독일입니다.

x는 분명히 ‘하위 표현’이 아닙니다.

이 진술은 또한 거짓입니다. 각 예에서 번의 하위 표현식 입니다.

‘평가’하기보다는 비교를 위해로드되어야합니다.

나는 이것이 무엇을 의미하는지 전혀 모른다.

분명히 당신은 여전히 ​​많은 거짓 신념을 가지고 있습니다. 나의 충고는 당신의 거짓 신념이 진정한 신념으로 대체 될 때까지 사양을 읽는 것입니다.

이 질문은 자바에 특화되어 있으며 까다로운 인터뷰 질문을 위해 일반적으로 제작 된 파렴치한 비현실적인 구성과 달리 표현 x == (x = y)는 실제 프로젝트에서 나왔습니다.

표현의 출처는 질문과 관련이 없습니다. 이러한 표현에 대한 규칙은 명세서에 명확하게 설명되어 있습니다. 읽어!

비교 및 교체 관용구를 한 줄로 대체해야했습니다.

한 줄로 교체하면 코드를 읽는 독자에게 많은 혼란이 생겼으므로 선택이 잘못되었다고 제안합니다. 코드를 더 간결하지만 이해하기 어렵게 만드는 것은 승리가 아닙니다. 코드를 더 빨리 만들지 않을 것입니다.

또한, C 번호가있다 비교 대체 라이브러리 방법으로 할 수 있는 기계 명령어까지 jitted한다. Java 유형 시스템에서는 표현할 수 없으므로 Java에는 그러한 메소드가 없다고 생각합니다.


답변

연산자 우선 순위 및 연산자 평가 방법과 관련이 있습니다.

괄호 ‘()’가 우선 순위가 높고 연관성이 왼쪽에서 오른쪽입니다. 이 질문의 다음에 평등 ‘==’이 나오고 왼쪽에서 오른쪽으로 연관성이 있습니다. 할당 ‘=’이 마지막에 오며 오른쪽에서 왼쪽으로 연관성이 있습니다.

시스템 사용 스택은 식을 평가합니다. 식은 왼쪽에서 오른쪽으로 평가됩니다.

이제 원래 질문에 온다 :

int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false

첫 x (1)은 스택으로 푸시됩니다. 그러면 inner (x = y)가 평가되고 x (3) 값으로 스택됩니다. 이제 x (1)은 x (3)과 비교되므로 결과는 false입니다.

x = 1; // reset
System.out.println((x = y) == x); // true

여기서 (x = y)가 평가되고 이제 x 값이 3이되고 x (3)이 스택으로 푸시됩니다. 이제 등식 후 변경된 값을 가진 x (3)이 스택으로 푸시됩니다. 이제 표현이 평가되고 둘 다 동일하므로 결과가 참입니다.


답변

동일하지 않습니다. 왼쪽은 항상 오른쪽보다 먼저 평가되며 괄호는 실행 순서를 지정하지 않고 명령 그룹을 지정합니다.

와:

      x == (x = y)

기본적으로 다음과 같은 작업을 수행합니다.

      x == y

그리고 x 는 비교 후 y 값을 갖습니다 .

함께하는 동안 :

      (x = y) == x

기본적으로 다음과 같은 작업을 수행합니다.

      x == x

xy 값을 취한
후 그리고 항상 true를 반환 합니다 .


답변

첫 번째 테스트에서 1 == 3을 수행합니다.

두 번째 테스트에서 검사는 3 == 3을 수행합니다.

(x = y)는 값을 할당하고 해당 값을 테스트합니다. 앞의 예에서 x = 1부터 x에 3이 할당됩니다. 1 == 3입니까?

후자에서 x에는 3이 할당되고 분명히 3입니다. 3 == 3입니까?