Java 使用i+;1、&x2B+;我认为这有什么不同?
简单介绍一下Java,让我先说一下:由于性能优化,我并不担心这一点,只是对一般的幕后工作感到好奇。因为我没有发现这一点,所以我假设它们在各个方面都是等效的,但为了确保:Java 使用i+;1、&x2B+;我认为这有什么不同?,java,optimization,increment,function-calls,Java,Optimization,Increment,Function Calls,简单介绍一下Java,让我先说一下:由于性能优化,我并不担心这一点,只是对一般的幕后工作感到好奇。因为我没有发现这一点,所以我假设它们在各个方面都是等效的,但为了确保: 在递归函数foo(inti)中,或者我猜在函数调用的一般情况下,foo(++i)和foo(i+1)之间有区别吗?我知道结果是一样的,但我想带++I的那个可能会在后台做一些额外的工作,因为它是一个作业?因此,它可能会在后台创建一个(匿名字段)=i,它会递增然后被引用? 或者编译器只是将++i优化为i+1 正如你所看到的,我的理解有
在递归函数
foo(inti)
中,或者我猜在函数调用的一般情况下,foo(++i)
和foo(i+1)
之间有区别吗?我知道结果是一样的,但我想带++I
的那个可能会在后台做一些额外的工作,因为它是一个作业?因此,它可能会在后台创建一个(匿名字段)=i
,它会递增然后被引用?
或者编译器只是将++i
优化为i+1
正如你所看到的,我的理解有点模糊,因此我们将不胜感激
编辑以澄清:
起初,这是由于一个递归函数,例如
public static int foo(int i) {
return (i >= 4) ? 0
: i + foo(++i);
}
“一般的功能”一部分出现在写问题的中间,如所说的,使这个模棱两可。希望这能澄清一切。
< P>如果<代码> i>代码>在<代码> FoO(++i)之后,值将被改变foo(int i)
{
//process stuff A
foo(i + 1);
//process stuff B
}
bar(int i)
{
//process stuff A
bar(i + 1);
//process stuff B
}
如果在foo(i+1)
之后处理i
,则该值不会更改
foo(int i)
{
//process stuff A
foo(i + 1);
//process stuff B
}
bar(int i)
{
//process stuff A
bar(i + 1);
//process stuff B
}
根据
//处理文件B
中的内容,您可能希望使用i+1
并使i
的值相同,或者++i
并使i
增加i如果在foo(++i)
之后使用i
,则值将发生更改
foo(int i)
{
//process stuff A
foo(i + 1);
//process stuff B
}
bar(int i)
{
//process stuff A
bar(i + 1);
//process stuff B
}
如果在foo(i+1)
之后处理i
,则该值不会更改
foo(int i)
{
//process stuff A
foo(i + 1);
//process stuff B
}
bar(int i)
{
//process stuff A
bar(i + 1);
//process stuff B
}
根据//process stuff B
中的内容,您可能希望使用i+1
并使i
的值相同,或者++i
并使i
递增执行foo(++i)
和foo(i+1)没有区别
:传递给foo
的参数值相同
然而,在前一种情况下,局部变量i
增加1;在后一种情况下,它保留其原始值
因此,如果您两次调用相同的方法,则会有不同:
foo(++i);
foo(++i); // Invoke with i 1 greater than before.
不同于
foo(i + 1);
foo(i + 1); // Invoke with the same argument
因此,一般来说,编译器无法优化任何东西,因为它们具有不同的语义。在执行foo(++i)
和foo(i+1)
时没有区别:传递给foo
的参数值是相同的
然而,在前一种情况下,局部变量i
增加1;在后一种情况下,它保留其原始值
因此,如果您两次调用相同的方法,则会有不同:
foo(++i);
foo(++i); // Invoke with i 1 greater than before.
不同于
foo(i + 1);
foo(i + 1); // Invoke with the same argument
因此,一般来说,编译器无法优化任何内容,因为它们具有不同的语义。在使用前缀增量后,除了关于i
值的其他注释之外。生成的字节码有一点不同。请参见下面的简化结果
foo(++i)编译为
iinc
iload_1
invokestatic
iload_1
iconst_1
iadd
invokestatic
foo(i+1)编译为
iinc
iload_1
invokestatic
iload_1
iconst_1
iadd
invokestatic
除了使用前缀增量后有关i
值的其他注释之外。生成的字节码有一点不同。请参见下面的简化结果
foo(++i)编译为
iinc
iload_1
invokestatic
iload_1
iconst_1
iadd
invokestatic
foo(i+1)编译为
iinc
iload_1
invokestatic
iload_1
iconst_1
iadd
invokestatic
是的,++i由两个操作加法和赋值组成。由于以后不需要i,因此使用i+1比使用++i更好。是的,++i由两个操作加法和赋值组成。由于以后不需要i,使用i+1比使用++i更好。如果答案不是关于语义,而是关于IR优化、转换为机器指令后机器级别的性能,我会说,“不,除非另行测量和证明。”
<>代码>在<代码> f(++)i >代码>和<代码> f(i+1)之间进行优化后,不太可能出现性能差异,假设您的代码是这样的,实际上您可以将这些视为备选方案(假设“代码< > <代码>的状态在函数调用之后不再相关”)。
这只是基本的硬件和编译器设计,已经存储在寄存器中的内存指令的成本,甚至在一个半胜任的编译器中优化这些代码到相同机器代码的简单性(我认为Java的JIT至少会是这样)。编译器的一个基本特性是识别不必要的副作用并彻底消除它们(事实上,这也是为什么人工微级别基准测试可能会产生误导的原因之一,除非它们以防止优化器直接跳过某些代码的方式非常仔细地编写)。最容易消除的副作用是这样一种情况,我们增加一个变量,i
,但不取决于之后的状态变化
这似乎不太可能对绩效产生任何实际影响。当然,最终的方法是查看最终生成的机器代码(不是字节码IR,而是实际的最终机器代码),或者测量并分析它。但至少可以说,如果一个比另一个快,我会非常震惊,这会让我觉得编译器在指令选择或寄存器分配方面做得很差
也就是说,如果一个比另一个快(很遥远的机会),我认为这是向后的<代码>++i
可能需要更少的工作,因为它只需增加寄存器中的一个值++i
是对一个操作数的一元运算,它适用于可变寄存器i+1
是一个表达式,它要求将i
视为不可变,并将调用seco