我有以下代码:
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作为值?
–update
这是字节码:
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
}
我会读到关于instructions试图了解…
解决方法:
注意:最初我在本答案中发布了C#代码用于说明,因为C#允许您通过ref关键字引用传递int参数.我决定使用我在Google上找到的第一个MutableInt
类来使用实际的合法Java代码更新它,以便对C#中的ref进行排序.我无法确定这是否有助于或伤害答案.我会说我个人没有做过那么多Java开发;所以我知道可能有更多的惯用方法来说明这一点.
也许如果我们写出一个方法来做相当于x的方法,它会使这个更清楚.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
对?增加传递的值并返回原始值:这是postincrement运算符的定义.
现在,让我们看看您的示例代码中这种行为是如何发挥作用的:
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.
你固定的事实是,当你用y替换上面赋值左侧的x时,“你可以看到它首先递增x,然后将它归属为y”让我感到困惑.它不是分配给y的x;它是以前分配给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的值为x0,然后是x0 1,然后是x0.
更新:顺便说一句,为了避免你怀疑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的不规则出现.
Starting background thread... 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 1