다음 코드가 있습니다.
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
식의 반환 값은 초기 값 인 x
0입니다. 그러나 나중에의 값을 읽을 때 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);
}