为什么在for循环的迭代部分不改变pre到post的增量会有所不同?
为什么这样呢
int x = 2; for (int y =2; y>0;y--){ System.out.println(x + " "+ y + " "); x++; }
打印与此相同?
int x = 2; for (int y =2; y>0;--y){ System.out.println(x + " "+ y + " "); x++; }
到目前为止,据我所知,首先使用“按原样”使用后增量,然后递增。 是否首先添加预增量然后使用。 为什么这不适用于for循环的主体?
循环相当于:
int x = 2; { int y = 2; while (y > 0) { System.out.println(x + " "+ y + " "); x++; y--; // or --y; } }
从阅读该代码可以看出,在for循环的第三部分中使用post或pre decrement运算符无关紧要。
更一般地说,任何for循环的forms:
for (ForInit ; Expression ; ForUpdate) forLoopBody();
完全等同于while循环:
{ ForInit; while (Expression) { forLoopBody(); ForUpdate; } }
for循环更紧凑,因此更容易解析这种常见的习语。
要想象这些东西,请将for循环展开为while循环:
for (int i = 0; i < 5; ++i) { do_stuff(i); }
扩展到:
int i = 0; while (i < 5) { do_stuff(i); ++i; }
无论是对循环计数器进行后递增还是预递增都无关紧要,因为增量表达式的结果(在递增之前或之后的值)不在同一语句中使用。
如果这是您的关注,那么在性能方面没有区别。 在增量期间 使用它时 ,它只能被错误地使用(因此对错误敏感)。
考虑:
for (int i = 0; i < 3;) System.out.print(++i + ".."); //prints 1..2..3 for (int i = 0; i < 3;) System.out.print(i++ + ".."); //prints 0..1..2
要么
for (int i = 0; i++ < 3;) System.out.print(i + ".."); //prints 1..2..3 for (int i = 0; ++i < 3;) System.out.print(i + ".."); //prints 1..2
然而,有趣的细节是,正常的习惯用法是在for
语句的增量表达式中使用i++
,并且Java编译器将编译它,就像使用++i
。
++ i和i ++与赋值运算符结合使用时会有所不同,例如int num = i ++和int num = ++ i或其他表达式。 在上面的FOR循环中,只有递增条件,因为它不与任何其他表达式结合使用,它没有任何区别。 在这种情况下,它只表示i = i + 1。
这个循环与while
循环相同:
int i = 0; while(i < 5) { // LOOP i++; // Or ++i }
所以是的,它必须是一样的。
因为这个陈述就是它自己的。 增量的顺序在那里并不重要。
这两种情况是等价的,因为在增量语句完成后比较i的值。 但是,如果你这样做了
if (i++ < 3)
与
if (++i < 3)
你必须担心事情的顺序。
如果你这样做了
i = ++i + i++;
那你就疯了。
因为您的示例中没有任何内容使用从增量前或后增量返回的值。 尝试围绕++x
和x++
包装System.out.println()
以查看差异。
从for循环中的Java语言规范章节 :
BasicForStatement:
for ( ForInit ; Expression ; ForUpdate ) Statement
…如果存在ForUpdate部分,则从左到右依次计算表达式; 它们的值(如果有的话)被丢弃。 …如果ForUpdate部件不存在,则不执行任何操作。
(突出显示是我的)。
输出是相同的,因为’for(initial; comparison; increment)’中的’increment’项不使用语句的结果 ,它只依赖于语句的副作用 ,在这种情况下是递增’i’,这两种情况都是一样的。
在评估增量参数之前完成检查。 ‘increment’操作在循环结束时完成,即使它在开头声明。
试试这个例子:
int i = 6; System.out.println(i++); System.out.println(i); i = 10; System.out.println(++i); System.out.println(i);
你应该能够弄清楚它的作用。
因为y
的值是在for
语句中计算的, x
的值是在它自己的行中计算的,但是在System.out.println
它们只被引用。
如果在System.out.println
递减,则会得到不同的结果。
System.out.println(y--); System.out.println(--y);
这里有很多好的答案,但如果这有帮助:
将y–和-y视为具有副作用的表达式,或者后跟表达式的语句。 y–是这样的(把这些例子想象成伪assembly):
decrement y return y
而且 – 这样做:
store y into t decrement y load t return t
在循环示例中,您将丢弃返回的值,并且仅依赖于副作用(循环检查在执行递减语句之后发生;它不接收/检查递减返回的值)。
如果for
循环使用了表达式i++
或++i
的结果,那么它就是真的,但事实并非如此,只是因为它的副作用。
这就是为什么你也可以在那里放一个void
方法,而不仅仅是一个数值表达式。
增量作为独立语句执行。 所以
y–;
和
–y;
相当于彼此,两者相当于
y = y – 1;
因为这:
int x = 2; for (int y =2; y>0; y--){ System.out.println(x + " "+ y + " "); x++; }
编译器有效地将其翻译为:
int x = 2; int y = 2 while (y > 0){ System.out.println(x + " "+ y + " "); x++; y--; }
如您所见,使用y--
或--y
不会产生任何差异。 如果你像这样编写你的循环会有所不同:
int x = 2; for (int y = 3; --y > 0;){ System.out.println(x + " "+ y + " "); x++; }
这将产生与循环的两个变体相同的结果,但是从--y
变为y--
这将破坏您的程序。
这是一个品味问题。 他们做同样的事情。
如果你看一下java类的代码,你会看到带有post-increment的for循环。
在你的情况下,它是相同的,没有任何区别。
你是对的。 在这种情况下可以看出差异:
for(int i = 0; i < 5; ) { System.out.println("i is : " + ++i); }
是的它按顺序执行。 初始化,然后是评估条件,如果是,则执行正文然后递增。
只有在使用递增/递减进行分配操作时,才会显示前缀和后缀差异。
没有区别,因为“参数”的每个部分都是分开的语句。
有趣的是,编译器可以决定通过预增量替换简单的后增量,这不会改变代码。
他们的行为不一样。 使用i ++的构造比使用++ i的构造略慢,因为前者涉及返回i的旧值和新值。 另一方面,后者只返回i的旧值。
然后,由于性能原因,编译器可能会做一点魔术并将任何隔离的i ++更改为++ i ,但就原始算法而言,它们并不完全相同。
Stackoverflow上有很多类似的post:
- 循环中i ++和++ i之间的区别?
- C#中的++ i和i ++之间是否存在任何性能差异?
- C ++中的i ++和++ i之间是否存在性能差异?
但是,似乎您的问题更通用,因为它并不特定于任何语言或编译器。 上述大多数问题都涉及特定的语言/编译器。
这是一个纲要:
- 如果我们谈论C / C ++ / Java(可能也是C#)和现代编译器:
- 如果
i
是一个整数(const int
,int
等):- 然后编译器基本上用
++i
替换i++
,因为它们在语义上是相同的,所以它不会改变输出。 这可以通过检查生成的代码/字节码来validation(对于Java,我使用jclasslib字节码查看器 )。
- 然后编译器基本上用
- 其他:
- 如果
- 其他:
- 所有的赌注都是关闭的,因为编译器不能保证它们在语义上是相同的,所以它不会尝试优化。
因此,如果你有一个C ++类,它会覆盖后缀和前缀运算符(比如std::iterator
),那么这种优化很少(如果有的话)完成。
综上所述:
- 意思是你说什么,说出你的意思。 对于
for
循环的增量部分,您几乎总是需要前缀版本(即++i
)。 -
++i
和i++
之间的编译器切换器并不总是可以完成,但是如果可以的话,它会尝试为你做。
在循环,首次初始化,然后条件检查,然后执行,在增加/减少之后。 所以前/后递增/递减不会影响程序代码。
关于i ++(增量后)与++ i(预增量)@me:“在这两种情况下,表达式都会被计算,结果用于检查条件。在预增量的情况下,增量表达式增加变量并返回结果值。对于后增量,增量表达式也会增加变量,但它会返回先前的值。因此,预增量与增量值进行比较,而后增量则与增量值进行比较。原始值;在这两种情况下,当检查条件时变量已经增加。“ – tdammers
在post和pre increment操作符之间存在相当混乱,这可以从“算法,Robert Sedgewick和Kevin Wayne的第4版”摘录中轻松理解。
递增/递减运算符:i ++与i = i + 1相同,并且在表达式中具有值i。 类似地,i–与i = i – 1相同。代码++ i和 – i是相同的,除了表达式值是在递增/递减之后,而不是之前。
例如
x = 0; post increment: x++; step 1: assign the old value (0) value of the x back to x.So, here is x = 0. step 2: after assigning the old value of the x, increase the value of x by 1. So, x = 1 now; when try to print somthing like: System.out.print(x++); the result is x : 0. Because only step one is executed which is assigning old value of the x back and then print it. But when, we do operation like this: i++; System.out.print(i); the result is x: 1. which is because of executing Step one at first statement and then step two at the second statement before printing the value. pre increment: ++x; step 1: increase the value of x by 1. So, x = 1 now; step 2: assign the increased value back to x. when try to print something like: System.out.print(++1) the result is x : 1. Because the value of the x is raised by 1 and then printed. So, both steps are performed before print x value. Similarly, executing ++i; system.out.print(i); Both steps are executed at statement one. At second statement, just the value of "i" is printed.