왜 무한 루프 상태가 되는 거죠?
다음 코드가 있습니다.
public class Tests {
public static void main(String[] args) throws Exception {
int x = 0;
while(x<3) {
x = x++;
System.out.println(x);
}
}
}
는 그가 것을 있다.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#에서는 패스할 수 있기 때문에, 당초, 이 회답에 C# 코드를 게재했습니다.int
에 ref
키워드를 지정합니다.구글에서 찾은 첫 번째 클래스를 사용하여 실제 합법 자바 코드로 업데이트하기로 했습니다.ref
C# 서 c 。그게 해답에 도움이 될지 해가 될지 잘 모르겠어요.저는 개인적으로 자바 개발을 그렇게 많이 하지 않았다고 말할 것입니다.그래서 제가 아는 한 이 점을 설명할 수 있는 더 많은 관용적인 방법이 있을 것입니다.
를 들어, '와 것을 할 수 있는 요?x++
게게더 확확?
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
맞죠? 전달된 값을 증가시키고 원래 값을 반환합니다. 이것이 post increment 연산자의 정의입니다.
이제 이 동작이 예제 코드에서 어떻게 수행되는지 살펴보겠습니다.
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)
incre? 증분 분증x
네, 그리고 증가하기 전의 것을 반환합니다.이 반환값은 다음에 할당됩니다.x
.
, 「」에 되어 있는 입니다.x
1, 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가 알 수 라고 헷갈립니다.은 아니다.x
되어 있다y
; 이것은 이전에 할당된 값입니다.실제로, 주입,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의 값이0 x, 다음으로0 x + 1, 그리고 다시0 x가 됩니다.
업데이트: 덧붙여서 다음과 같은 점을 의심하지 않도록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이 모두 불규칙하게 발생한다는 점에 유의하십시오.
백그라운드 스레드를 시작하는 중... 00110000000000101
x = x++
작용합니다.
- 을 평가합니다.
x++
식을 , 이x
increment)및(증가전)를 실시합니다.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: icstore_1 // 스택에서 x로의 pop 값
은, 「」의이 「」이기 때문에 합니다.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
that그의 이다.x
, 「」입니다.0
을 사용하다iinc 1, 1
값: " " " "1
1
x
이 now now now가 되다1
.istore_1
: 의 값은 됩니다.「 」1
그것은0
is is is is is 。x
증가된 값을 덮어씁니다.
에, 「」의 은 「」, 「」x
는 변경되지 않고 무한 루프가 발생합니다.
- 프레픽스 표기법은 식을 평가하기 전에 변수를 증가시킵니다.
- 표현식 평가 후 포스트픽스 표기법이 증가합니다.
",,=
의는 "보다.++
★★★★★★★★★★★★★★★★★.x=x++;
과 같이
x
★★★★★★★★★★★★★★★★★★★★★★★★★★x
- 값 " " " "
x
할당되어 있습니다.x
.
어느 대답도 정확하지 않습니다.그러면, 다음과 같습니다.
을 when when when 를 쓸 때int x = x++
를 하는 것이 .x
값이 「새로운 값」을 하는 것입니다.x
으로 하다x++
which 。 게 of의 값입니다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
갱신된 값, 즉1 을 수신합니다.
그것은 이미 다른 사람들에 의해 잘 설명되었다.관련 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);
}
답은 꽤 간단하다.사물이 평가되는 순서와 관련이 있습니다. x++
합니다.x
후, 「」가 증분합니다.x
.
결과, 식 、 현 、 현 、 현 、 consequ 、 consequ 、 consequ consequ consequ consequ 。x++
0
, 「」를 할당하고 것이군요x=0
루프의 각 시간마다.입니다.x++
는 이 값을 증가시키지만 할당 전에 이 값이 증가합니다.
http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html 에서
증가/감소 연산자는 피연산자 앞(prefix) 또는 피연산자 뒤에 적용할 수 있습니다.코드 result++; 및 ++result;는 둘 다 1씩 증가합니다.유일한 차이점은 프리픽스버전(++result)은 증가된 값으로 평가되지만 포스트픽스버전(result++)은 원래 값으로 평가됩니다.단순한 증감만 실행하는 경우 어떤 버전을 선택하든 상관없습니다.그러나 더 큰 식에 이 연산자를 사용하는 경우 선택한 연산자에 따라 상당한 차이가 있을 수 있습니다.
예를 들어, 다음을 시험해 보겠습니다.
int x = 0;
int y = 0;
y = x++;
System.out.println(x);
System.out.println(y);
그러면 1과 0이 출력됩니다.
무슨 일이 일어나고 있는지 알기 위해 기계 코드가 꼭 필요한 것은 아닙니다.
정의에 따라:
할당 연산자는 오른쪽 식을 평가하여 임시 변수에 저장합니다.
1.1. x의 현재 값이 이 임시 변수로 복사됩니다.
이제 1.2. x가 증가합니다.
그런 다음 임시 변수가 식 왼쪽(우연히 x)에 복사됩니다.그래서 x의 오래된 값이 다시 그 자체로 복사되는 것입니다.
그것은 꽤 간단하다.
사실상 다음과 같은 행동을 하게 됩니다.
- 오른쪽의 "결과"로서 x 값(0)을 잡다
- x의 값을 증가시킵니다(x는 1이 됩니다).
- 오른쪽(0으로 저장)의 결과를 x에 할당합니다(x는 현재 0).
이 개념은 해당 변수가 사용된 방정식에 사용할 값을 반환한 후 해당 변수가 증가한다는 것입니다.
편집: 코멘트로 인해 약간의 추가가 이루어지고 있습니다.이렇게 생각해 보세요.
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.
이 경우 절대 증가하지 않기 때문입니다. x++
는 이
x = 0;
만약 이 한다면++x;
이 값은 증가합니다.
으로 유지되기 때문입니다.그 이유는 값이x++
는 0 이에요. 이 경우에는 x
여부에 은 """입니다x=0
실행됩니다.이로 인해 일시적으로 증가된 값이 덮어쓰게 됩니다.x
('1월 1일')은 1은 1월 1일.
이것은 당신이 기대하는 대로 작동합니다.프리픽스와 포스트픽스의 차이입니다.
int x = 0;
while (x < 3) x = (++x);
x++는 증분 전의 X를 "반환"하는 함수 호출이라고 생각하십시오(그래서 이것이 사후 증분이라고 불립니다).
조작 순서는 다음과 같습니다.
x 후 증가시킨다1: 가기 x 을 1 1 1 。
: 증가 x2: 증가 x
값x을합니다.3: 캐시된 값(증가하기 전의 x)을 반환합니다.
됩니다: 반환값은 x4에 할당됩니다.
++가 rhs에 있으면 값이 증가하기 전에 결과가 반환됩니다.++x로 변경하시면 됩니다.Java는 증분이 아닌 단일 연산(x to x 할당)을 수행하도록 최적화했습니다.
이 에러는, 할당이 증가치를 덮어쓰기 해, 증가전의 값을 덮어쓰기 해, 즉 증가분을 원래대로 되돌리기 때문에 발생합니다.
특히, "x++" 식에는 "+x"가 증가하기 전에 "x" 값이 있고, "+x"는 증가 후에 "x" 값이 있습니다.
바이트 코드의 조사에 관심이 있는 경우는, 다음의 3 행에 대해 설명합니다.
7: iload_1
8: iinc 1, 1
11: istore_1
두 번째 합니다.iload_1 # load 、 load 7 7 7 。
8:1.1 두 입니다!8: iinc 1.1#은 스택을 변경하지 . 스택은 변경되지 않은 상태로 유지됩니다.
# 이을 두 로컬 9: icstore_1 # 에 합니다.
(각 JVM 명령의 효과는 여기에서 확인할 수 있습니다.)
따라서 위의 코드는 무한정 루프되지만 ++x 버전에서는 루프되지 않습니다.++x의 바이트코드는 상당히 다르게 보일 것입니다.제가 1년 전에 작성한 1.3 Java 컴파일러에서 기억하기로는 바이트코드는 다음과 같습니다.
iinc 1,1
iload_1
istore_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;
줄에 서 있는 것.
x = x++; (increment is overriden by = )
위의 문장으로 인해 x는 3에 도달하지 않는다.
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
무관해야 합니다.어느쪽이든 유효하다고 생각합니다.
이 동작에 따라 달라지는 코드를 작성하는 것은 매우 조심하고 싶습니다.구현에 매우 의존적인 것으로 보입니다.스펙의 크랙스 사이에 있는 것 같습니다.여기서와 같이 엉뚱한 행동을 했을 경우나 두 개의 스레드가 실행되고 식 내의 평가 순서에 의존했을 경우만 차이가 있습니다.
Java ++는 =(수정)보다 우선도가 높기 때문에...그런가요?http://www.cs.uwf.edu/ ~ 장어 / cop2253 / op_incellence . http://www.cs.uwf.edu/ 를 참조해 주세요.
x=x+1이라고 하는 것과 같은 방법으로...+가 =보다 우선 순위가 높습니다(기준).
x++
표현하면 '아까운명하다.x
. 。++
부품은 평가 후 값에 영향을 미치지만 문장이 아닌 값에 영향을 미칩니다.x = x++
으로 번역되다
int y = x; // evaluation
x = x + 1; // increment part
x = y; // assignment
값을 1씩 늘리기 전에 값이 변수에 할당됩니다.
포스트가 증가했기 때문에 일어나는 일입니다.표현식이 평가된 후 변수가 증가함을 의미합니다.
int x = 9;
int y = x++;
x는 10이지만 y는 9입니다.이 값은 증가하기 전의 x 값입니다.
자세한 내용은 포스트 인크리먼트의 정의를 참조해 주세요.
아래 코드를 확인합니다.
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
이것은 루프에 있습니다(코드의 첫 번째 줄은 제외).★★★★★★★★!!!
증분 연산자는 할당하는 변수와 동일한 변수에 적용됩니다.그건 말썽을 부리는 거야.이 프로그램을 실행하는 동안 x 변수의 값을 볼 수 있을 것입니다.루프가 끝나지 않는 이유를 명확히 할 수 있을 거예요
언급URL : https://stackoverflow.com/questions/3831341/why-does-this-go-into-an-infinite-loop
'programing' 카테고리의 다른 글
vuex 스토어에서 특정 상태가 변경될 때 이벤트 발생 (0) | 2022.07.03 |
---|---|
v-list 항목 vue + vuetify를 클릭하여 v-radio를 선택하는 방법 (0) | 2022.07.03 |
증명서를 Import한 후 Java Keytool 오류가 발생했습니다.keytool error : java.ioFile Not Found Exception 및 접근 거부" (0) | 2022.07.03 |
Vue 구성 요소 vuex 저장소 상태 속성이 이미 데이터로 채워졌는지 확인합니다. (0) | 2022.07.03 |
Spring의 ApplicationContext.getBean이 불량으로 간주되는 이유는 무엇입니까? (0) | 2022.07.03 |