我有以下代码:
public class Tests { public static void main(String[] args) throws Exception { int x = 0; while(x<3) { x = x++; System.out.println(x); } } }
我们知道他应该只写x++or x=x+1,但x = x++应该首先在其上归因x于自身,然后再增加它。为什么x继续使用0as 值?
x++
x=x+1
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。我决定使用MutableInt我在 Google 上找到的第一个类用实际合法的 Java 代码来更新它,以近似refC# 中的功能。我真的不知道这是否有助于或伤害答案。我会说我个人还没有做过那么多的 Java 开发。所以据我所知,可能有更多惯用的方法来说明这一点。
int
ref
MutableInt
也许如果我们写出一个方法来做相当于做什么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.
postIncrement(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使事情与上述情况没有什么不同。我们得到了:
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到控制台。
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