为了账号安全,请及时绑定邮箱和手机立即绑定

为什么 Java 不优化 |= 赋值?

为什么 Java 不优化 |= 赋值?

杨__羊羊 2021-10-27 10:06:51
t*()对于此示例,始终返回 true,而f*()始终返回 false。假设我们有以下表达式if ( f1() || t1() || f2() || t2() ){    // do stuff        }如果是这种情况,JVM 会优化执行并仅执行,f1()并且t1()因为它“理解”无论什么f2()和t2()yield,都满足了输入 if 语句的要求,因此不需要进一步的计算。我正在编写这样的代码:boolean b = false;b |= f1(); // Ab |= t1(); // Bb |= f2(); // Cb |= t2(); // D我的一位同事看到了这一点,并提到他不确定,但 Java 有可能优化语句 C 和 D,因为b总是true从语句B开始,这可能会导致一些问题。我进行了一些测试,似乎所有测试都被正确执行(这是所需的行为),但我仍然想知道为什么这没有得到优化?我想他可能是对的,JVM 知道一旦b为真|=,对它的任何操作都不会改变它的值。
查看完整描述

3 回答

?
慕雪6442864

TA贡献1812条经验 获得超5个赞

由于JLS §15.26.2,调用不会被优化掉复合赋值运算符需要计算右侧的表达式。

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

  • 首先,评估左边的操作数以产生一个变量。如果这个评估突然完成,那么赋值表达式也会因为同样的原因突然完成;不计算右侧操作数,也不进行赋值。

  • 否则,保存左侧操作数的值,然后评估右侧操作数。

  • ...

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


查看完整回答
反对 回复 2021-10-27
?
撒科打诨

TA贡献1934条经验 获得超2个赞

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

因为那将违反 JLS。

该声明

b |= f1();

相当于

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

另外,在上述中,JLS要求b | f1()如下评价:

  1. 获取 的值b

  2. 调用f1()并捕获结果值

  3. |运算符应用于两个值。

该JLS不会让编译器跳过通话f1(),如果btrue1

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


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


查看完整回答
反对 回复 2021-10-27
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

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

|=化合物运算符是一个位操作符,这意味着两个术语进行了评价。

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

断点将始终触发。

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

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


查看完整回答
反对 回复 2021-10-27
  • 3 回答
  • 0 关注
  • 138 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信