Skip to content

Commit 4f40d04

Browse files
authored
Merge pull request giantray#77 from bboylin/master
finished translating Why does this go into an infinite loop
2 parents 29d6d73 + 0ae910d commit 4f40d04

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
## 这段代码为什么陷入了死循环
2+
3+
### 问题
4+
我写了这样一段代码
5+
6+
```java
7+
public class Tests {
8+
public static void main(String[] args) throws Exception {
9+
int x = 0;
10+
while(x<3) {
11+
x = x++;
12+
System.out.println(x);
13+
}
14+
}
15+
}
16+
```
17+
18+
我们知道他应该只写x++或者x=x+1就行了,但是x=x++的情况下,x应该先赋值给自己,然后再增加1。为什么X的值一直是0呢?
19+
20+
--更新
21+
</br>下面是字节码
22+
23+
```java
24+
public class Tests extends java.lang.Object{
25+
public Tests();
26+
Code:
27+
0: aload_0
28+
1: invokespecial #1; //Method java/lang/Object."<init>":()V
29+
4: return
30+
31+
public static void main(java.lang.String[]) throws java.lang.Exception;
32+
Code:
33+
0: iconst_0
34+
1: istore_1
35+
2: iload_1
36+
3: iconst_3
37+
4: if_icmpge 22
38+
7: iload_1
39+
8: iinc 1, 1
40+
11: istore_1
41+
12: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
42+
15: iload_1
43+
16: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
44+
19: goto 2
45+
22: return
46+
47+
}
48+
```
49+
50+
51+
### 回答
52+
53+
一开始我用C#代码来解释,因为C#允许用"ref"关键字来实现int参数的引用传递,所以我决定用我google到的MutableInt类写的标准的java代码来模拟C#中ref关键字作用.我不知道这对我的解答是不是有帮助,我并不是一个专业的java开发者,我知道还有很多更符合语言习惯的方法去解释这个问题。
54+
也许我写一个函数来模拟x++的作用会解释得更清楚
55+
56+
```java
57+
public MutableInt postIncrement(MutableInt x) {
58+
int valueBeforeIncrement = x.intValue();
59+
x.add(1);
60+
return new MutableInt(valueBeforeIncrement);
61+
}
62+
```
63+
64+
对不对?将传递的参数值加1然后返回原值,这就是后增操作符的定义。
65+
现在让我们看看在你的代码中是怎么执行的。
66+
67+
```java
68+
MutableInt x = new MutableInt();
69+
x = postIncrement(x);
70+
```
71+
72+
`postIncrement(x)`函数做了什么?x增加1,对,然后返回x加1之前的值,并且把该返回值赋给x。所以X被赋值的顺序是0,1,0。如果我们重写上面的代码会理解得更清楚。
73+
74+
```java
75+
MutableInt x = new MutableInt(); // x is 0.
76+
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
77+
x = temp; // Now x is 0 again.
78+
```
79+
80+
你定势地认为,将左边的X换个名称为y,"你能看到x先自增1,然后赋值给了y",这一时也让我有点困惑。bi那个不是x被赋值给y,而是x(自增)之前的值被赋给y.事实上,把左边x变量名改成y结果也没什么不同。
81+
82+
```java
83+
MutableInt x = new MutableInt(); // x is 0.
84+
MutableInt y = new MutableInt(); // y is 0.
85+
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
86+
y = temp; // y is still 0.
87+
```
88+
89+
可见,x=x++并没有改变x的值,只是让x依次被赋值为x0,x0+1,x0。
90+
91+
更新:你可能会怀疑在自增过程中x并没有被赋值为1,下面通过一个demo来解释确实x存在赋值为1的过程。
92+
demo中调用了x=x++;同时另外开了一个单独的线程不断输出x的值.
93+
94+
```java
95+
public class Main {
96+
public static volatile int x = 0;
97+
98+
public static void main(String[] args) {
99+
LoopingThread t = new LoopingThread();
100+
System.out.println("Starting background thread...");
101+
t.start();
102+
103+
while (true) {
104+
x = x++;
105+
}
106+
}
107+
}
108+
109+
class LoopingThread extends Thread {
110+
public @Override void run() {
111+
while (true) {
112+
System.out.println(Main.x);
113+
}
114+
}
115+
}
116+
```
117+
118+
下面是程序的部分输出,0和1不规则的出现。
119+
120+
```
121+
Starting background thread...
122+
0
123+
0
124+
1
125+
1
126+
0
127+
0
128+
0
129+
0
130+
0
131+
0
132+
0
133+
0
134+
0
135+
0
136+
1
137+
0
138+
1
139+
```
140+
141+
142+
stackoverflow链接:
143+
[http://stackoverflow.com/questions/3831341/why-does-this-go-into-an-infinite-loop](http://stackoverflow.com/questions/3831341/why-does-this-go-into-an-infinite-loop)

0 commit comments

Comments
 (0)