为什么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,其中as
f*()
始终返回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
被赋值为literal
true
,然后将
|=
赋值给一个方法,该方法返回
布尔值,并在其中有一个断点,您可以很容易地调试该测试

断点将始终触发

另一方面,“快捷方式”优化仅适用于布尔运算符:
|
&&


注意:一些关于复合赋值的规范,但我在
|=
赋值中找不到相关部分

调用不会得到优化,因为需要计算右侧表达式

如果左侧操作数表达式不是数组访问表达式,则:

  • 首先,对左侧操作数求值以生成 一个变量。如果此评估突然完成,则分配 表达出于同样的原因突然完成;右手 不计算操作数,也不进行赋值
  • 否则,将保存左侧操作数的值,然后计算右侧操作数。

从历史上看,条件(
&&
|
)运算符的传统至少可以追溯到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我在您发布的链接中找不到特定语句?