2

t*()对于本例,总是返回 true,而 asf*()总是返回 false。

假设我们有以下表达式

if ( f1() || t1() || f2() || t2() ){
    // do stuff        
}

如果是这种情况,JVM 会优化执行并仅执行f1()t1()因为它“理解”无论如何f2()t2()yield,输入 if 语句的要求得到满足,因此不需要进一步的计算。

我正在编写这样的代码:

boolean b = false;
b |= f1(); // A
b |= t1(); // B
b |= f2(); // C
b |= t2(); // D

我的一位同事看到了这一点并提到他不确定,但 Java 可能会优化语句 C 和 D,因为b总是true从语句B开始,这可能会导致一些问题。

我进行了一些测试,似乎所有测试都正确执行(这是所需的行为),但我仍然想知道为什么不进行优化?我认为他可能是对的,JVM 明白一旦b为真,任何|=操作都不会改变它的值。

4

3 回答 3

4

由于JLS §15.26.2,调用没有得到优化。复合赋值运算符需要计算右侧表达式。

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

  • 首先,评估左侧操作数以产生变量。如果这个求值突然完成,那么赋值表达式也会因为同样的原因而突然完成;不计算右侧操作数,也不发生赋值。
  • 否则,将保存左侧操作数的值,然后计算右侧操作数。

  • ...

从历史上看,短路条件 ( &&, ||) 而不是位 ( &, |) 运算符的传统至少可以追溯到 C (但可能值得注意的是,C 直到 1999 年才具有明确的布尔类型)。

于 2018-10-03T13:32:28.990 回答
3

我仍然想知道为什么这没有得到优化?

因为那将违反 JLS。

该声明

b |= f1();

相当于

b = (boolean)(b | f1());

在上面,JLS要求b | f1()按如下方式评估:

  1. 获取 的值b
  2. 调用f1()并捕获结果值
  3. |运算符应用于这两个值。

如果为1,JLS不允许编译器跳过调用。f1()btrue

如果你想要那种语义(短路),你需要使用b = b || f1();等等。(如您所述:b ||= f1()是语法错误。)


1 - 实际上,在无法观察(在单线程程序中)f1()调用发生或未发生的情况下,理论上优化是允许的。但是您只能通过仔细检查JIT 编译器发出的本机代码来检测优化。只有在调用严格无副作用时才会发生这种情况。

于 2018-10-03T13:43:32.560 回答
1

这更多地是关于布尔运算符和按位运算符之间的区别。

复合运算符是按位运算符,这|=意味着对这两个项都求值。

您可以通过设置一个测试来轻松调试它,其中b分配了 literal true,然后|=分配给返回任一boolean值的方法,并在其中有一个断点。

断点将始终触发。

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

注意:这里有一些关于复合分配的规范,但我找不到关于|=分配的相关部分。

于 2018-10-03T13:31:23.303 回答