为什么Java不优化|=赋值?
本例中,为什么Java不优化|=赋值?,java,binary-operators,conditional-execution,Java,Binary Operators,Conditional Execution,本例中,t*()始终返回true,其中asf*()始终返回false 假设我们有下面的表达式 if ( f1() || t1() || f2() || t2() ){ // do stuff } 如果是这种情况,JVM将优化执行,并且只执行f1()和t1(),因为它“理解”无论发生什么f2()和t2()屈服,都满足了输入If语句的要求,因此不需要进一步计算 我正在编写一个代码,我写了如下内容: boolean b = false; b |= f1(); // A b |
t*()
始终返回true,其中asf*()
始终返回false
假设我们有下面的表达式
if ( f1() || t1() || f2() || t2() ){
// do stuff
}
如果是这种情况,JVM将优化执行,并且只执行
f1()
和t1()
,因为它“理解”无论发生什么f2()
和t2()
屈服,都满足了输入If语句的要求,因此不需要进一步计算
我正在编写一个代码,我写了如下内容:
boolean b = false;
b |= f1(); // A
b |= t1(); // B
b |= f2(); // C
b |= t2(); // D
我的一位同事看到了这一点,并提到他不确定,但Java可能会优化语句C和D,因为从语句b
开始,b
总是true
,这可能会导致一些问题
我进行了一些测试,似乎所有测试都正确执行(这是期望的行为),但是我仍然想知道为什么这不能得到优化?我想他可能是对的,JVM知道一旦
b
为真,对它的=
操作就不会改变它的值。这更多的是关于布尔运算符和位运算符之间的区别
|=
复合运算符是位运算符,这意味着两个术语都要求值
通过设置一个测试,其中b
被赋值为literaltrue
,然后将|=
赋值给一个方法,该方法返回布尔值,并在其中有一个断点,您可以很容易地调试该测试
断点将始终触发
另一方面,“快捷方式”优化仅适用于布尔运算符:|
和&&
注意:一些关于复合赋值的规范,但我在|=
赋值中找不到相关部分 调用不会得到优化,因为需要计算右侧表达式
如果左侧操作数表达式不是数组访问表达式,则:
- 首先,对左侧操作数求值以生成
一个变量。如果此评估突然完成,则分配
表达出于同样的原因突然完成;右手
不计算操作数,也不进行赋值
- 否则,将保存左侧操作数的值,然后计算右侧操作数。
从历史上看,条件(&&
,|
)运算符的传统至少可以追溯到C(但值得注意的是,C直到1999年才有显式布尔类型),而不是按位(&
,|
)
我仍然想知道为什么这个没有得到优化
因为这违反了JLS
声明
b |= f1();
相当于
b = (boolean)(b | f1());
在上述情况下,JLS要求对b | f1()
进行如下评估:
获取b
的值
调用f1()
并捕获结果值
将|
运算符应用于这两个值
如果b
为true
1,JLS不允许编译器跳过调用f1()
如果您需要这种语义(短路),则需要使用b=b | | f1()代码>等等。(正如您所指出的:b | |=f1()
是一个语法错误。)
1-实际上,在无法观察(在单线程程序中)调用是否发生f1()
的情况下,理论上允许进行优化。但您只能通过仔细检查JIT编译器发出的本机代码来检测优化。只有在调用完全没有副作用的情况下才会发生这种情况。无论如何,如果编译器执行了您建议的操作,我会感到惊讶。如果我看到的代码如您所描述的那样编写,我肯定不会期望您这样做。一个问题可能是,运算符=
不是布尔或(|
),而是二进制或(|
)…”如果是这种情况,JVM会优化执行,并且只执行“这不是在JVM中完成的,而是语言的一部分”。如果查看字节码,方法调用后将跳转到块后。我将b |=f2()
更改为b=b | | f2()
,它会短路。@Sun它确实跳过对f2()
的求值,但仍然执行整个语句。。如果两个操作数都是布尔值,则为逻辑运算符。@AndyTurner我在您发布的链接中找不到特定语句?