Tom*_*ito 490 java loops increment operators variable-assignment
我有以下代码:
public class Tests {
public static void main(String[] args) throws Exception {
int x = 0;
while(x<3) {
x = x++;
System.out.println(x);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们知道他应该只是写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
}
Run Code Online (Sandbox Code Playgroud)
我会读到有关试图理解的说明 ......
Dan*_*Tao 353
注意:最初我在本答案中发布了C#代码用于说明,因为C#允许您int通过引用传递参数和ref关键字.我决定使用MutableInt我在Google上找到的第一个类来实际使用合法的Java代码来更新它,以便对refC#中的内容进行近似处理.我无法确定这是否有助于或伤害答案.我会说我个人没有做过那么多Java开发; 所以我知道可能有更多的惯用方法来说明这一点.
也许如果我们写出一个方法来做相同的事情x++,它会使这更清楚.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
Run Code Online (Sandbox Code Playgroud)
对?增加传递的值并返回原始值:这是postincrement运算符的定义.
现在,让我们看看您的示例代码中这种行为是如何发挥作用的:
MutableInt x = new MutableInt();
x = postIncrement(x);
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)
当你x在上面的作业的左侧替换为y"你可以看到它首先递增x,然后将它归因于y" 这一事实时,你固定的事实让我感到困惑.它不是x被分配给y; 它是以前赋予的价值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.
Run Code Online (Sandbox Code Playgroud)
所以很清楚:x = x++有效地不会改变x的值.它总是使x的值为x 0,然后是x 0 + 1,然后再次为x 0.
更新:顺便说一句,为了避免你怀疑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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下是上述程序输出的摘录.注意1和0的不规则出现.
Starting background thread... 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 1
axt*_*avt 169
x = x++ 以下列方式工作:
x++.对该表达式的求值产生表达式值(它是x增量前的值)和增量x.x,覆盖递增的值.因此,事件序列如下所示(它是一个实际的反编译字节码,由javap -c我的评论产生):
8: iload_1 // Remember current value of x in the stack 9: iinc 1, 1 // Increment x (doesn't change the stack) 12: istore_1 // Write remebered value from the stack to x
为了比较,x = ++x:
8: iinc 1, 1 // Increment x 11: iload_1 // Push value of x onto stack 12: istore_1 // Pop value from the stack to x
cod*_*ict 104
发生这种情况是因为它的值x根本没有增加.
x = x++;
Run Code Online (Sandbox Code Playgroud)
相当于
int temp = x;
x++;
x = temp;
Run Code Online (Sandbox Code Playgroud)
说明:
我们来看看这个操作的字节代码.考虑一个示例类:
class test {
public static void main(String[] args) {
int i=0;
i=i++;
}
}
Run Code Online (Sandbox Code Playgroud)
现在运行类反汇编程序,我们得到:
$ 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
}
Run Code Online (Sandbox Code Playgroud)
现在Java VM是基于堆栈的,这意味着对于每个操作,数据将被推送到堆栈和堆栈,数据将弹出以执行操作.还有另一种数据结构,通常是用于存储局部变量的数组.局部变量给出id,它们只是数组的索引.
让我们来看看助记符中main()方法:
iconst_0:常量值0
被推送到堆栈.istore_1:弹出堆栈的顶部元素并将其存储在索引1 x.iload_1:在该位置处的值1是值的x
是0,被压入堆栈.iinc 1, 1:内存位置的1值递增1.所以x现在变成了
1.istore_1:堆栈顶部的值存储在内存位置1.这被0指定为x 覆盖其递增的值.因此,值x不会改变,从而导致无限循环.
Jay*_*dee 52
但是" ="的运算符优先级低于" ++".
所以x=x++;应评估如下
x 准备分配(评估)x 增加 x分配给的值x.Rob*_*anu 34
没有一个答案在哪里,所以这里是:
当你在写作时int x = x++,你并没有指定x自己处于新值,而是指定x为x++表达式的返回值.x正如Colin Cochrane的回答所示,这恰好是原始价值.
为了好玩,请测试以下代码:
public class Autoincrement {
public static void main(String[] args) {
int x = 0;
System.out.println(x++);
System.out.println(x);
}
}
Run Code Online (Sandbox Code Playgroud)
结果将是
0
1
Run Code Online (Sandbox Code Playgroud)
表达式的返回值是初始值x,为零.但是稍后,当读取值时x,我们会收到更新的值,即一个.
小智 29
它已经被其他人很好地解释了.我只是包含相关Java规范部分的链接.
x = x ++是一个表达式.Java将遵循评估顺序.它将首先计算表达式x ++,它将增加x并将结果值设置为x的前一个值.然后它将表达式结果赋给变量x.最后,x返回其先前的值.
cle*_*tus 18
这个说法:
x = x++;
Run Code Online (Sandbox Code Playgroud)
评估如下:
x到堆栈上;x;x从堆栈弹出.所以价值没有变化.比较一下:
x = ++x;
Run Code Online (Sandbox Code Playgroud)
评估为:
x;x到堆栈上;x从堆栈弹出.你想要的是:
while (x < 3) {
x++;
System.out.println(x);
}
Run Code Online (Sandbox Code Playgroud)
Mik*_*nes 10
答案很简单.它与评估事物的顺序有关.x++返回值x然后递增x.
因此,表达式的值x++是0.所以你x=0在循环中每次分配.当然会x++增加此值,但这在分配之前发生.
来自http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html
可以在操作数之前(前缀)或之后(后缀)应用递增/递减运算符.代码结果++; 和++结果; 两个结果都会以一个增加结果.唯一的区别是前缀版本(++结果)评估为增量值,而后缀版本(结果++)评估为原始值.如果您只是执行简单的增量/减量,那么选择哪个版本并不重要.但是,如果您在较大的表达式中使用此运算符,则您选择的运算符可能会产生显着差异.
为了说明,请尝试以下方法:
int x = 0;
int y = 0;
y = x++;
System.out.println(x);
System.out.println(y);
Run Code Online (Sandbox Code Playgroud)
其中将打印1和0.
您有效地获得了以下行为.
这个想法是后增量运算符(x ++)增加有问题的变量AFTER返回它的值以便在它使用的等式中使用.
编辑:由于评论而添加一点点.考虑如下.
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.
Run Code Online (Sandbox Code Playgroud)
小智 7
您并不真正需要机器代码来了解正在发生的事情.
根据定义:
赋值运算符计算右侧表达式,并将其存储在临时变量中.
1.1.x的当前值被复制到此临时变量中
1.2.x现在递增.
然后将临时变量复制到表达式的左侧,这是偶然的x!这就是x的旧值再次复制到自身的原因.
这很简单.
这是因为在这种情况下它永远不会增加.x++在增加之前将首先使用它的值,就像在这种情况下它会像:
x = 0;
Run Code Online (Sandbox Code Playgroud)
但如果你这样做++x;会增加.
| 归档时间: |
|
| 查看次数: |
22447 次 |
| 最近记录: |