为什么这会进入无限循环? [英] Why does this go into an infinite loop?

查看:42
本文介绍了为什么这会进入无限循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

公共类测试{public static void main(String[] args) 抛出异常 {整数 x = 0;而(x<3){x = x++;System.out.println(x);}}}

我们知道他应该只写 x++x=x+1,但是在 x = x++ 上,它应该首先属性 x 到自身,然后增加它.为什么 x 继续以 0 作为值?

--更新

这是字节码:

public class Tests extends java.lang.Object{公共测试();代码:0:aload_01:调用特殊#1;//方法java/lang/Object."":()V4:返回public static void main(java.lang.String[]) 抛出 java.lang.Exception;代码:0:iconst_01:istore_12:iload_13:iconst_34:if_icmpge 227: iload_18: 国际公司 1, 111:istore_112:getstatic #2;//字段 java/lang/System.out:Ljava/io/PrintStream;15: iload_116:invokevirtual #3;//方法java/io/PrintStream.println:(I)V19:转到222:返回}

我会阅读有关说明的内容以尝试理解...

解决方案

注意:最初我在此答案中发布了 C# 代码以进行说明,因为 C# 允许您传递 int 参数通过 ref 关键字引用.我决定使用第一个 MutableInt 类是我在 Google 上找到的,它近似于 ref 在 C# 中的作用.我真的不知道这是否有助于或伤害了答案.我会说我个人并没有做过那么多的 Java 开发.所以就我所知,可能有更多惯用的方式来说明这一点.

<小时>

也许如果我们写出一个方法来完成 x++ 所做的事情,它会更清楚这一点.

public MutableInt postIncrement(MutableInt x) {int valueBeforeIncrement = x.intValue();x.添加(1);返回新的 MutableInt(valueBeforeIncrement);}

对吧?递增传递的值并返回原始值:这就是后递增运算符的定义.

现在,让我们看看这种行为在您的示例代码中的表现:

MutableInt x = new MutableInt();x = postIncrement(x);

postIncrement(x) 做什么?增量 x,是的.然后返回增量之前的x .然后将此返回值分配给 x.

因此分配给 x 的值的顺序是 0,然后是 1,然后是 0.

如果我们重写上面的内容可能会更清楚:

MutableInt x = new MutableInt();//x 为 0.MutableInt temp = postIncrement(x);//现在 x 为 1,temp 为 0.x = 温度;//现在 x 又是 0.

您对以下事实的关注:当您将上述赋值左侧的 x 替换为 y 时,您可以看到它首先增加了 x,然后将其归因于 y"让我感到困惑.分配给 y 的不是 x;它是 以前分配给 x 的值.真的,注入 y 与上面的场景没有什么不同;我们只有:

MutableInt x = new MutableInt();//x 为 0.MutableInt y = new MutableInt();//y 为 0.MutableInt temp = postIncrement(x);//现在 x 为 1,temp 为 0.y = 温度;//y 仍然是 0.

所以很明显:x = x++ 实际上不会改变 x 的值.它总是使 x 具有值 x0,然后是 x0 + 1,然后又是 x0.

<小时>

更新:顺便说一下,为了避免您怀疑 x 是否曾经在增量操作"和上面示例中的赋值之间被赋值为 1,我已将它们放在一起一个快速演示来说明这个中间值确实存在",尽管它永远不会在执行线程上看到".

该演示在循环中调用 x = x++;,同时一个单独的线程不断地将 x 的值打印到控制台.

public class Main {公共静态易失性 int x = 0;公共静态无效主(字符串 [] args){LoopingThread t = new LoopingThread();System.out.println("正在启动后台线程...");t.start();而(真){x = x++;}}}类 LoopingThread 扩展线程 {公共@Override void run() {而(真){System.out.println(Main.x);}}}

以下是上述程序输出的摘录.注意 1 和 0 的不规则出现.

<前>正在启动后台线程...00110000000000101

I have the following code:

public class Tests {
    public static void main(String[] args) throws Exception {
        int x = 0;
        while(x<3) {
            x = x++;
            System.out.println(x);
        }
    }
}

We know he should have writen just x++ or x=x+1, but on x = x++ it should first attribute x to itself, and later increment it. Why does x continue with 0 as value?

--update

Here's the bytecode:

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

}

I'll read about the instructions to try to understand...

解决方案

Note: Originally I posted C# code in this answer for purposes of illustration, since C# allows you to pass int parameters by reference with the ref keyword. I've decided to update it with actual legal Java code using the first MutableInt class I found on Google to sort of approximate what ref does in C#. I can't really tell if that helps or hurts the answer. I will say that I personally haven't done all that much Java development; so for all I know there could be much more idiomatic ways to illustrate this point.


Perhaps if we write out a method to do the equivalent of what x++ does it will make this clearer.

public MutableInt postIncrement(MutableInt x) {
    int valueBeforeIncrement = x.intValue();
    x.add(1);
    return new MutableInt(valueBeforeIncrement);
}

Right? Increment the value passed and return the original value: that's the definition of the postincrement operator.

Now, let's see how this behavior plays out in your example code:

MutableInt x = new MutableInt();
x = postIncrement(x);

postIncrement(x) does what? Increments x, yes. And then returns what x was before the increment. This return value then gets assigned to x.

So the order of values assigned to x is 0, then 1, then 0.

This might be clearer still if we re-write the above:

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.

Your fixation on the fact that when you replace x on the left side of the above assignment with y, "you can see that it first increments x, and later attributes it to y" strikes me as confused. It is not x that is being assigned to y; it is the value formerly assigned to x. Really, injecting y makes things no different from the scenario above; we've simply got:

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.

So it's clear: x = x++ effectively does not change the value of x. It always causes x to have the values x0, then x0 + 1, and then x0 again.


Update: Incidentally, lest you doubt that x ever gets assigned to 1 "between" the increment operation and the assignment in the example above, I've thrown together a quick demo to illustrate that this intermediate value does indeed "exist," though it will never be "seen" on the executing thread.

The demo calls x = x++; in a loop while a separate thread continuously prints the value of x to the console.

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);
        }
    }
}

Below is an excerpt of the above program's output. Notice the irregular occurrence of both 1s and 0s.

Starting background thread...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1

这篇关于为什么这会进入无限循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆