이것이 왜 무한 루프에 빠 집니까?


493

다음 코드가 있습니다.

public class Tests {
    public static void main(String[] args) throws Exception {
        int x = 0;
        while(x<3) {
            x = x++;
            System.out.println(x);
        }
    }
}

우리는 그가 just x++또는 을 작성 했어야한다는 것을 알고 x=x+1있지만, x = x++우선 x그 자체에 귀속 하고 나중에 증가 시켜야 합니다. 왜 가치를 x계속 유지 0합니까?

--최신 정보

바이트 코드는 다음과 같습니다.

public class Tests extends java.lang.Object{
public Tests();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_3
   4:   if_icmpge   22
   7:   iload_1
   8:   iinc    1, 1
   11:  istore_1
   12:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   15:  iload_1
   16:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   19:  goto    2
   22:  return

}

이해하려고 하는 지침 에 대해 읽겠습니다 ...


8
무슨 일이 일어나고 있는지 의심합니다 : 1. 레지스터에 x를로드 (= 0); 2. 증분 x (x = 1); 3. 레지스터 값을 x (x = 0)에 저장합니다. C / C ++에서는 2와 3의 순서를 정의하는 공식적인 순서 지점이 없기 때문에 이것은 정의되지 않은 동작입니다. 누군가 Java 스펙과 동등한 것을 인용 할 수 있기를 바랍니다.
Rup

19
우리는 C ++에서 이것을 시도하여 어떤 일이 일어날 지 확인하고 1,2,3을 인쇄하고 종료합니다. 나는 그것을 기대하지 않았다. 정의되지 않은 동작이기 때문에 컴파일러에 따라 다릅니다. 우리는 gnu g ++를 사용했습니다.
30.10에 슬픔

13
@saj x++는 증가 후입니다. 결과x= 할당 ; 결과 의는 원래이다 (그리고 증가의 부작용이있다,하지만 결과는 변경되지 않습니다)이이로 해석 될 수 있도록,x++xvar tmp = x; x++; x = tmp;
마크 Gravell

5
이제 유감스럽게도 인기있는 질문이 있으므로 정답을 선택한 후에도 (반복 된) 답변이 더 이상 나오지 않습니다. 나의 "최근 활동"화면은 같은 대답으로 가득 차 있으며 더 많이옵니다 ...
Tom Brito

3
@Rob Vermeulen 당신은 코멘트를 만들기 전에 전체 질문을 읽고 싶을 수도 있습니다.
Tom Brito

답변:


354

참고 : 원래 C #을 사용하면 키워드 int를 참조하여 매개 변수 를 전달할 수 있으므로 설명을 위해이 답변에 C # 코드를 게시했습니다 ref. C #에서 수행 MutableInt하는 것과 비슷한 것을 찾기 위해 Google에서 찾은 첫 번째 클래스를 사용하여 실제 법적 Java 코드로 업데이트하기로 결정했습니다 ref. 그게 답을 돕는 지 또는 아프게하는지 알 수 없습니다. 필자는 개인적으로 그렇게 많은 Java 개발을하지 않았다고 말할 것이다. 내가 아는 한,이 점을 설명하는 훨씬 더 관용적 인 방법이있을 수 있습니다.


아마도 우리가하는 것과 동등한 것을 수행하는 방법을 x++작성하면 이것이 더 명확해질 것입니다.

public MutableInt postIncrement(MutableInt x) {
    int valueBeforeIncrement = x.intValue();
    x.add(1);
    return new MutableInt(valueBeforeIncrement);
}

권리? 전달 된 값을 증가시키고 원래 값을 리턴하십시오. 이것이 증분 후 연산자의 정의입니다.

이제 예제 코드에서이 동작이 어떻게 수행되는지 봅시다 :

MutableInt x = new MutableInt();
x = postIncrement(x);

postIncrement(x)무엇을합니까? 증가 x, 예. 그리고 무엇을 반환 x 했다 증가하기 전에 . 그런 다음이 반환 값이에 할당됩니다 x.

따라서 할당 된 값의 순서 x는 0, 1, 0입니다.

위의 내용을 다시 쓰면 더 명확해질 수 있습니다.

MutableInt x = new MutableInt();    // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp;                           // Now x is 0 again.

x위 과제의 왼쪽에서을로 바꾸면 y"먼저 x를 증가시키고 나중에 속성을 y로 표시하는 것을 볼 수 있습니다" 라는 사실에 대한 당신의 고정 은 혼란스러워합니다. 그것은 그것에 x할당 되지 않습니다 y; 그것에는 이전에 할당 된 값x . 실제로 주입 y은 위의 시나리오와 다르지 않습니다. 우리는 단순히 다음을 얻었습니다.

MutableInt x = new MutableInt();    // x is 0.
MutableInt y = new MutableInt();    // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp;                           // y is still 0.

따라서 분명합니다. x = x++x의 값을 효과적으로 변경하지 않습니다. 항상 x는 값 X가 원인이 0 이면, x 0 + 1을 입력 한 다음 X 0 다시.


업데이트 : 우연히, x위의 예제에서 증가 연산과 할당 사이에 1 "할당"이 할당되는 것을 의심하지 않도록 이 중간 값이 실제로 "존재"한다는 것을 설명하기 위해 빠른 데모를 함께 작성했습니다. 실행중인 스레드에서 "보이지"마십시오.

x = x++;별도의 스레드가 지속적으로 x콘솔에 값을 인쇄하는 동안 데모 는 루프를 호출합니다 .

public class Main {
    public static volatile int x = 0;

    public static void main(String[] args) {
        LoopingThread t = new LoopingThread();
        System.out.println("Starting background thread...");
        t.start();

        while (true) {
            x = x++;
        }
    }
}

class LoopingThread extends Thread {
    public @Override void run() {
        while (true) {
            System.out.println(Main.x);
        }
    }
}

아래는 위 프로그램 출력의 일부입니다. 1과 0이 불규칙적으로 나타납니다.

백그라운드 스레드 시작 중 ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1

1
자바에서 참조로 전달하기 위해 클래스를 만들 필요는 없습니다 (확실히 작동 할지라도). Integer표준 라이브러리의 일부인 클래스 를 사용할 수 있으며 int 거의 투명하게 자동 상자를 만들 수 있다는 이점도 있습니다.
rmeador

3
@rmeador Integer는 변경할 수 없으므로 여전히 값을 변경할 수 없습니다. 그러나 AtomicInteger는 변경 가능합니다.
ILMTitan

5
@ Dan : 그건 그렇고, x마지막 예제에서 선언해야합니다 volatile. 그렇지 않으면 정의되지 않은 동작이며 1s는 구현에 따라 다릅니다.
axtavt

4
@burkestar : 그 링크는 생각하지 않습니다 아주 는 자바 질문이기 때문에,이 경우에 적절하고 (내가 잘못이야 제외) 동작은 실제로 C ++로 정의되어 있지 않습니다.
Dan Tao

5
@Tom Brito-C에서는 정의되지 않았습니다 ... 할당 전후에 수행 ++ 할 수 있습니다. 실제로 Java와 동일한 기능을 수행하는 컴파일러가있을 수 있지만 그에 베팅하고 싶지 않을 것입니다.
detly

170

x = x++ 다음과 같은 방식으로 작동합니다.

  • 먼저 expression을 평가합니다 x++. 이 표현식의 평가는 표현식 값 ( x증분 전의 값)과 증가를 생성 x합니다.
  • 나중에 표현식 값을에 할당하여 x증분 값을 덮어 씁니다.

따라서 이벤트 시퀀스는 다음과 같습니다 ( javap -c내 의견과 함께 생성 된 실제 디 컴파일 된 바이트 코드입니다 ).

   8 : iload_1 // 스택에서 x의 현재 값 기억
   9 : iinc 1, 1 // 증가 x (스택을 변경하지 않음)
   12 : istore_1 // 스택에서 x로 기억 된 값을 씁니다.

비교를 위해 x = ++x:

   8 : iinc 1, 1 // 증가 x
   11 : iload_1 // x의 값을 스택에 푸시
   12 : istore_1 // 스택에서 x로 값 팝

테스트를 수행하면 테스트가 먼저 증가하고 나중에 속성이 증가 함을 알 수 있습니다. 따라서 0의 속성이 아니어야합니다.
톰 브리토

2
@Tom 그게 요점입니다. 이것은 모두 단일 시퀀스이기 때문에 불명확하고 (아마도 정의되지 않은) 순서로 일을하고 있습니다. 이것을 테스트하려고하면 시퀀스 포인트를 추가하고 다른 동작을 얻습니다.
Rup

바이트 코드 출력과 관련하여 iinc변수 를 증가 시키면 스택 값이 증가하지 않으며 스택에 값을 남기지 않습니다 (거의 다른 모든 산술 연산과 달리). ++x비교 를 위해 생성 한 코드를 추가 할 수 있습니다 .
Anon

3
@Rep C 또는 C ++로 정의되지 않았지만 Java에서는 잘 정의되어 있습니다.
ILMTitan


104

이는 값 x이 전혀 증가하지 않기 때문에 발생 합니다.

x = x++;

에 해당

int temp = x;
x++;
x = temp;

설명:

이 작업을위한 바이트 코드를 보자. 샘플 클래스를 고려하십시오.

class test {
    public static void main(String[] args) {
        int i=0;
        i=i++;
    }
}

이제 클래스 디스어셈블러를 실행하면 다음과 같은 결과를 얻습니다.

$ javap -c test
Compiled from "test.java"
class test extends java.lang.Object{
test();
  Code:
   0:    aload_0
   1:    invokespecial    #1; //Method java/lang/Object."<init>":()V
   4:    return

public static void main(java.lang.String[]);
  Code:
   0:    iconst_0
   1:    istore_1
   2:    iload_1
   3:    iinc    1, 1
   6:    istore_1
   7:    return
}

이제 Java VM 은 스택을 기반으로하므로 각 작업마다 데이터가 스택으로 푸시되고 스택에서 데이터가 팝업되어 작업을 수행합니다. 또 다른 데이터 구조, 일반적으로 지역 변수를 저장하는 배열이 있습니다. 지역 변수에는 배열에 대한 색인 인 id가 제공됩니다.

방법론 의 니모닉 을 살펴 보자 main().

  • iconst_0: 상수 값 0 이 스택으로 푸시됩니다.
  • istore_1: 스택의 최상위 요소가 튀어 나와 인덱스가 1
    있는 로컬 변수에 저장됩니다 x.
  • iload_1: 위치의 값 1의 값 x 이는이 0스택으로 푸시된다.
  • iinc 1, 1: 메모리 위치의 값 1이 씩 증가합니다 1. 그래서 x지금이된다 1.
  • istore_1: 스택 상단의 값이 메모리 위치에 저장됩니다 1. 즉됩니다 0에 할당 x 덮어 쓰기 의 증분 값입니다.

따라서 값이 x변경되지 않아 무한 루프가 발생합니다.


5
실제로는 증분 ++되지만 (즉, 의 의미 ) 변수는 나중에 덮어 씁니다.
Progman

10
int temp = x; x = x + 1; x = temp;예를 들어 타우 톨로지를 사용하지 않는 것이 좋습니다.
Scott Chamberlain

52
  1. 접두사 표기법은 표현식이 평가되기 전에 변수를 증가시킵니다.
  2. 접미사 표기법은 표현식 평가 후에 증가합니다.

그러나 " ="는 " "보다 연산자 우선 순위가 낮습니다 ++.

따라서 x=x++;다음과 같이 평가해야합니다

  1. x 과제 준비 (평가)
  2. x 증분
  3. 에 이전 값이 x할당되었습니다 x.

이것이 가장 좋은 대답입니다. 일부 마크 업은 조금 더 눈에 띄는 데 도움이되었을 것입니다.
저스틴 포스

1
이것은 잘못이다. 우선 순위가 아닙니다. C 및 C ++ ++보다 우선 순위가 높지만 =해당 언어에서는 명령문이 정의되지 않습니다.
Matthew Flaschen

2
원래 질문은 자바에 관한 것입니다
Jaydee

34

꽤 주목되는 답변은 없으므로 다음과 같이하십시오.

당신이 글을 쓸 때 int x = x++, 당신은 x그 자체로 새로운 가치를 부여받지 않고 x, x++표현 의 반환 가치를 부여 받습니다. Colin Cochrane의 답변x 에서 암시 된 것처럼 원래 값은 입니다.

재미있게 다음 코드를 테스트하십시오.

public class Autoincrement {
        public static void main(String[] args) {
                int x = 0;
                System.out.println(x++);
                System.out.println(x);
        }
}

결과는

0
1

식의 반환 값은 초기 값 인 x0입니다. 그러나 나중에의 값을 읽을 때 x업데이트 된 값을받습니다.


나는 바이트 코드 라인을 이해하려고 노력할 것이고, 내 업데이트를 참조하십시오. 분명합니다. : :)
Tom Brito

println () 사용하면 이것을 이해하는 데 매우 도움이되었습니다.
ErikE

29

이미 다른 사람들에 의해 잘 설명되어 있습니다. 관련 Java 사양 섹션에 대한 링크 만 포함합니다.

x = x ++는 표현식입니다. Java는 평가 순서 를 따릅니다 . 먼저 x ++ 표현식을 평가하여 x 를 증가시키고 결과 값을 이전 값 x로 설정 합니다. 그런 다음 표현식 결과 를 변수 x에 할당합니다 . 결국 x는 이전 값으로 돌아갑니다.


1
+1. 이것은 실제 질문 인 "왜?"에 대한 최고의 답변입니다.
Matthew Flaschen

18

이 진술 :

x = x++;

다음과 같이 평가됩니다.

  1. x스택에 밀어 넣 습니다.
  2. 증가 x;
  3. x스택에서 튀어 나옵니다.

따라서 값은 변경되지 않습니다. 이것을 다음과 비교하십시오.

x = ++x;

다음과 같이 평가됩니다.

  1. 증가 x;
  2. x스택에 밀어 넣 습니다.
  3. x스택에서 튀어 나옵니다.

당신이 원하는 것은 :

while (x < 3) {
  x++;
  System.out.println(x);
}

13
확실히 올바른 구현이지만 문제는 '왜?'입니다.
p.campbell

1
원래 코드는 x에 증분 후를 사용한 다음 x에 할당했습니다. x는 증분 전에 x에 바인딩되므로 값이 변경되지 않습니다.
wkl

5
@cletus 나는 downvoter는 아니지만 초기 답변에는 설명이 포함되어 있지 않습니다. 방금 'x ++'라고 말했습니다.
Petar Minchev

4
@cletus : 나는 공감하지 않았지만 당신의 대답은 원래 x++코드 스 니펫이었습니다.
p.campbell

10
설명도 잘못되었습니다. 코드가 처음에 x를 x에 할당 한 다음 x를 증가 시키면 정상적으로 작동합니다. x++;솔루션을 변경 x=x; x++;하면 원래 코드가 주장하는 것을하고 있습니다.
Wooble

10

대답은 매우 간단합니다. 그것은 평가되는 순서와 관련이 있습니다. x++x을 반환 한 다음 증가 x합니다.

결과적으로 식의 값은 x++입니다 0. 따라서 x=0루프에서 매번 할당 합니다. x++이 값은 확실히 증가하지만 할당 전에 발생합니다.


1
와우, 대답이 짧고 간단 할 때이 페이지에 매우 자세한 내용이 있습니다.
Charles Goodwin

8

에서 http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html

증분 / 감소 연산자는 피연산자 이전 (접두사) 또는 이후 (접두사)에 적용될 수 있습니다. 코드 결과 ++; ++ 결과; 결과는 1 씩 증가합니다. 유일한 차이점은 접두사 버전 (++ result)이 증가 된 값으로 평가되고 접미사 버전 (result ++)은 원래 값으로 평가된다는 것 입니다. 단순한 증감 만 수행하는 경우 실제로 어떤 버전을 선택하든 문제가되지 않습니다. 그러나이 연산자를 더 큰 표현식의 일부로 사용하면 선택한 연산자가 크게 달라질 수 있습니다.

설명하기 위해 다음을 시도하십시오.

    int x = 0;
    int y = 0;
    y = x++;
    System.out.println(x);
    System.out.println(y);

1과 0을 인쇄합니다.


1
문제의 평가 결과는 아니지만 상점의 순서입니다.
Rup

2
동의하지 않습니다. X = 0이면, x ++ 0을 반환 따라서 X = X ++ X = 0에서 발생한다
콜린 코크

Rup이 이것에 관한 것입니다. 이 특정한 경우에 문제가되는 상점의 순서입니다. y = x ++는 x = x ++와 같지 않습니다. 후자에서 x는 같은 식으로 2 개의 값이 할당됩니다. 왼손 x 에는 식 x ++ 의 평가 결과 인 0 이 할당 됩니다. 오른쪽 x는 1로 증가합니다.이 2 개의 할당이 발생하는 순서는 문제입니다. 이전 게시물에서 이것이 작동하는 방식은 분명합니다 : eval = x ++ => eval == 0 : 오른쪽 x 증가 => x == 1 : 왼쪽 x = eval => x == 0
Michael Ekoka

7

효과적으로 다음과 같은 동작이 나타납니다.

  1. x의 값 (0)을 오른쪽의 "결과"로 가져옵니다.
  2. x 값을 증가 시키십시오 (그래서 x는 이제 1입니다)
  3. 오른쪽 (0으로 저장된)의 결과를 x (x는 이제 0)에 할당

후행 증가 연산자 (x ++)는 사용 된 방정식에서 사용할 값을 반환 한 후 해당 변수를 증가시킵니다.

편집 : 주석 때문에 약간의 비트 추가. 다음과 같이 고려하십시오.

x = 1;        // x == 1
x = x++ * 5;
              // First, the right hand side of the equation is evaluated.
  ==>  x = 1 * 5;    
              // x == 2 at this point, as it "gave" the equation its value of 1
              // and then gets incremented by 1 to 2.
  ==>  x = 5;
              // And then that RightHandSide value is assigned to 
              // the LeftHandSide variable, leaving x with the value of 5.

그러나 2 단계와 3 단계의 순서는 무엇입니까?
Rup

@Rup-언어가 정의합니다. 방정식의 우변이 먼저 평가되고 (이 경우 "x ++") 결과는 좌변의 변수에 지정됩니다. 언어가 작동하는 방식입니다. 방정식에 대해 "x ++" "returning"x까지는 접미사 증가 연산자가 작동하는 방식입니다 (x의 값을 반환 한 다음 증가). "--x"인 경우 (x를 증가시킨 다음 값을 리턴) 것입니다. 반품이 올바른 단어는 아니지만 아이디어를 얻습니다.
RHSeeger

7

무슨 일이 일어나고 있는지 이해하기 위해 실제로 기계 코드가 필요하지 않습니다.

정의에 따르면 :

  1. 대입 연산자는 오른쪽 표현식을 평가하여 임시 변수에 저장합니다.

    1.1. x의 현재 값이이 임시 변수에 복사됩니다

    1.2. 이제 x가 증가합니다.

  2. 그런 다음 임시 변수는 표현식의 왼쪽에 우연히 x입니다! 그래서 x의 이전 값이 다시 그 자체로 복사됩니다.

꽤 간단합니다.


5

이 경우에는 증분되지 않기 때문입니다. x++이 경우처럼 증가하기 전에 값을 먼저 사용합니다.

x = 0;

그러나 그렇게하면 ++x;증가합니다.


테스트를 수행하면 테스트가 먼저 증가하고 나중에 속성이 증가 함을 알 수 있습니다. 따라서 0의 속성이 아니어야합니다.
톰 브리토

1
@Tom : 내 대답 참조-테스트에서 x ++이 실제로 이전 값 x를 반환한다는 것을 보여줍니다. 그것이 깨지는 곳입니다.
Robert Munteanu

"테스트를한다면"-어떤 사람들은 C로 작성된 테스트가 자바가 무엇을하는지, C가 무엇을하는지 말해주지 않을 때 우리에게 무엇을 알려줄 것이라고 생각하는 것 같습니다.
Jim Balter

3

값이 0이므로 값이 0으로 유지 x++됩니다.이 경우 값 x이 증가 하는지 여부에 관계없이 할당 x=0이 실행됩니다. 임시 증분 값 x( "매우 짧은 시간"은 1)을 덮어 씁니다 .


그러나 x ++는 사후 작업입니다. 따라서 할당이 완료된 후 x를 증가시켜야합니다.
Sagar V

1
@Sagar V : x++전체 과제가 아닌 표현만을위한 것x=x++;
Progman

아니요, 과제에 사용될 x 값을 읽은 후에 만 ​​증가시켜야한다고 생각합니다.
Rup

1

이것은 다른 사람이 기대하는 방식으로 작동합니다. 접두사와 접미사의 차이점입니다.

int x = 0; 
while (x < 3)    x = (++x);

1

x ++를 X가 증분 이전에 있었던 것을 "반환"하는 함수 호출로 생각하십시오 (그 때문에 그것이 사후 증분이라고합니다).

따라서 작업 순서는 다음과 같습니다.
1 : 증분 전에 x 값을 캐시합니다
. 2 : 증분 x
3 : 캐시 된 값을 반환합니다 (x는 증분되기 전)
4 : 반환 값이 x에 할당됩니다


그러나 3 단계와 4 단계의 순서는 무엇입니까?
Rup

"증가하기 전의 X를 반환합니다"가 잘못되었습니다. 내 업데이트를 참조하십시오.
Tom Brito

실제로 3 단계와 4 단계는 별도의 작업이 아닙니다. 실제로 값을 반환하는 함수 호출이 아니며 , 그렇게 생각하는 데 도움이됩니다. 할당이있을 때마다 오른쪽이 "평가됨"이면 결과가 왼쪽에 할당됩니다. 평가 결과는 작업 순서를 이해하는 데 도움이되는 반환 값으로 생각할 수 있지만 실제로는 그렇지 않습니다. .
jhabbott

죄송합니다. 2 단계와 4 단계를 의미했습니다-반환 된 값이 증가 된 값의 상단에 왜 저장됩니까?
Rup

1
이는 할당 작업 정의의 일부이며, 먼저 오른쪽이 완전히 평가 된 다음 결과가 왼쪽에 지정됩니다.
jhabbott

1

++가 rhs에 있으면 숫자가 증가하기 전에 결과가 반환됩니다. ++ x로 변경하면 괜찮을 것입니다. Java는 증분이 아닌 단일 작업 (x를 x에 할당)을 수행하도록이를 최적화했습니다.


1

내가 알 수있는 한, 증분 이전 값으로 증분 값을 재정의하는 할당으로 인해 오류가 발생합니다. 즉, 증분을 취소합니다.

특히, "x ++"표현식은 증분 후 'x'값을 갖는 "++ x"와 반대로 증분 이전에 'x'값을 갖습니다.

바이트 코드 조사에 관심이 있다면 문제의 세 줄을 살펴 보겠습니다.

 7:   iload_1
 8:   iinc    1, 1
11:  istore_1

7 : iload_1 # 두 번째 로컬 변수의 값을 스택
8에 넣습니다. iinc 1,1 #은 두 번째 로컬 변수를 1 씩 증가시킵니다. 스택은 그대로 둡니다.
9 : istore_1 # 스택 상단을 팝업하고이 요소의 값을 두 번째 로컬 변수에 저장합니다
( 여기 에서 각 JVM 명령어의 영향을 읽을 수 있음 )

그렇기 때문에 위 코드가 무한정 반복되는 반면 ++ x 버전은 그렇지 않습니다. ++ x의 바이트 코드는 1 년 전에 조금 쓴 1.3 Java 컴파일러에서 기억하는 한 바이트 코드는 다음과 같아야합니다.

iinc 1,1
iload_1
istore_1

따라서 첫 번째 두 줄을 바꾸면 증가 후 스택 맨 위에 남은 값 (즉, 표현식의 '값')이 증가 후 값이되도록 의미가 변경됩니다.


1
    x++
=: (x = x + 1) - 1

그래서:

   x = x++;
=> x = ((x = x + 1) - 1)
=> x = ((x + 1) - 1)
=> x = x; // Doesn't modify x!

이므로

   ++x
=: x = x + 1

그래서:

   x = ++x;
=> x = (x = x + 1)
=> x = x + 1; // Increments x

물론 최종 결과는 저절로 x++;또는 ++x;한 줄로 동일 합니다.



0

Java 사양 에이 동작을 정확하게 정의하는 것이 있는지 궁금합니다. (이 진술의 명백한 함의는 확인하기에는 너무 게으르다는 것입니다.)

Tom의 바이트 코드에서 키 라인은 7, 8 및 11입니다. 라인 7은 x를 계산 스택에로드합니다. 8 행은 x를 증가시킵니다. 11 행은 스택의 값을 다시 x로 저장합니다. 자신에게 값을 다시 할당하지 않는 일반적인 경우에는로드, 저장 및 증분이 불가능한 이유가 있다고 생각하지 않습니다. 같은 결과를 얻을 수 있습니다.

마찬가지로보다 일반적인 경우를 다음과 같이 작성했다고 가정합니다. z = (x ++) + (y ++);

기술 여부를 설명하기위한 의사 코드

load x
increment x
add y
increment y
store x+y to z

또는

load x
add y
store x+y to z
increment x
increment y

관련이 없어야합니다. 구현이 유효해야한다고 생각합니다.

이 동작에 의존하는 코드 작성에 매우 신중합니다. 그것은 구현에 따라 크랙 사이의 스펙에 매우 의존적으로 보입니다. 차이를 만들 수있는 유일한 시간은 여기 예제와 같이 미친 짓을하거나 두 개의 스레드가 실행 중이고 표현식 내 평가 순서에 의존 한 경우입니다.



0

x++식을 평가 x. ++부분은 후에 값에 영향을 평가 하지 후, . 그래서 x = x++효과적으로

int y = x; // evaluation
x = x + 1; // increment part
x = y; // assignment

0

값을 1 씩 증가시키기 전에 값이 변수에 할당됩니다.


0

게시물이 증가했기 때문에 발생합니다. 이는 표현식이 평가 된 후 변수가 증가 함을 의미합니다.

int x = 9;
int y = x++;

x는 이제 10이지만 y는 9입니다. x는 증가하기 전의 x 값입니다.

Post Increment 정의 에서 더 많은 것을보십시오 .


1
귀하의 x/ y예제는 실제 코드와 다르며 차이점은 관련이 있습니다. 귀하의 링크에는 Java도 언급되어 있지 않습니다. 그것은 언어의 두 않습니다 언급, 질문의 문이 정의되어 있지 않습니다.
Matthew Flaschen

0

아래 코드를 확인하십시오.

    int x=0;
    int temp=x++;
    System.out.println("temp = "+temp);
    x = temp;
    System.out.println("x = "+x);

출력은

temp = 0
x = 0

post increment의미 는 값을 증가시키고 증가 전에 값을 반환 한다는 의미 입니다. 이것이 바로 가치 temp입니다 0. 그렇다면 어떻게 temp = i하고 이것이 루프에 있는지 (첫 번째 코드 줄 제외). 질문처럼 !!!!


-1

증가 연산자는 할당하는 것과 동일한 변수에 적용됩니다. 문제가 생겼습니다. 이 프로그램을 실행하는 동안 x 변수의 값을 볼 수 있다고 확신합니다 .... 루프가 끝나지 않는 이유를 분명히해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.