다음 코드가 있습니다.
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
}
이해하려고 하는 지침 에 대해 읽겠습니다 …
답변
참고 : 원래 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
답변
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로 값 팝
답변
이는 값 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변경되지 않아 무한 루프가 발생합니다.
답변
- 접두사 표기법은 표현식이 평가되기 전에 변수를 증가시킵니다.
- 접미사 표기법은 표현식 평가 후에 증가합니다.
그러나 ” =“는 ” “보다 연산자 우선 순위가 낮습니다 ++.
따라서 x=x++;다음과 같이 평가해야합니다
- x과제 준비 (평가)
- x증분
- 에 이전 값이 x할당되었습니다x.
답변
꽤 주목되는 답변은 없으므로 다음과 같이하십시오.
당신이 글을 쓸 때 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업데이트 된 값을받습니다.
답변
이미 다른 사람들에 의해 잘 설명되어 있습니다. 관련 Java 사양 섹션에 대한 링크 만 포함합니다.
x = x ++는 표현식입니다. Java는 평가 순서 를 따릅니다 . 먼저 x ++ 표현식을 평가하여 x 를 증가시키고 결과 값을 이전 값 x로 설정 합니다. 그런 다음 표현식 결과 를 변수 x에 할당합니다 . 결국 x는 이전 값으로 돌아갑니다.
답변
이 진술 :
x = x++;다음과 같이 평가됩니다.
- x스택에 밀어 넣 습니다.
- 증가 x;
- x스택에서 튀어 나옵니다.
따라서 값은 변경되지 않습니다. 이것을 다음과 비교하십시오.
x = ++x;다음과 같이 평가됩니다.
- 증가 x;
- x스택에 밀어 넣 습니다.
- x스택에서 튀어 나옵니다.
당신이 원하는 것은 :
while (x < 3) {
  x++;
  System.out.println(x);
}