Java f1()和#x2B的执行顺序;f2()*f3()表达式和运算符在JLS中的优先级

Java f1()和#x2B的执行顺序;f2()*f3()表达式和运算符在JLS中的优先级,java,operator-precedence,evaluation,jls,expression-evaluation,Java,Operator Precedence,Evaluation,Jls,Expression Evaluation,给定一个带有3个方法调用的表达式f1()+f2()*f3(),java首先计算加法运算的(操作数): 我(错误地)期望先调用f2(),然后调用f3(),最后调用f1()。因为乘法应该在加法之前计算 所以,我不明白这里-我错过了什么 15.7.3。求值尊重括号和优先级 Java编程语言尊重评估顺序 用括号显式表示,用运算符隐式表示 优先级。 在本例中,运算符优先级到底是如何得到尊重的 JLS在(方法调用表达式(§15.12.4)、方法引用表达式(§15.13.3))中提到了一些异常,但我无法将这些

给定一个带有3个方法调用的表达式
f1()+f2()*f3()
,java首先计算加法运算的(操作数):

我(错误地)期望先调用
f2()
,然后调用
f3()
,最后调用
f1()
。因为乘法应该在加法之前计算

所以,我不明白这里-我错过了什么

15.7.3。求值尊重括号和优先级

Java编程语言尊重评估顺序 用括号显式表示,用运算符隐式表示 优先级。

在本例中,运算符优先级到底是如何得到尊重的

JLS在(方法调用表达式(§15.12.4)、方法引用表达式(§15.13.3))中提到了一些异常,但我无法将这些异常应用到我的示例中

我知道JLS保证二进制运算的操作数从左到右求值。但是在我的示例中,为了理解方法调用序列,有必要首先理解哪个操作(以及它的两个操作数!)。我在这里错了吗?为什么

更多示例:

int result = f1() + f2()*f3() + f4() + f5()*f6() + (f7()+f8());
自豪地生产:

f1 working
f2 working
f3 working
f4 working
f5 working
f6 working
f7 working
f8 working
它是100%从左到右,完全不考虑运算符优先级

int result = f1() + f2() + f3()*f4();
产生:

f1 working
f2 working
f3 working
f4 working
f5 working
f6 working
f7 working
f8 working
f1 working
f2 working
f3 working
f4 working
在这里,编译器有两个选项:

  • f1()+f2()
    -先添加
  • f3()*f4()
    先乘法
  • 但是“从左到右评估规则”在这里很有魅力


    这意味着在此类示例中,无论括号和关联性规则如何,方法调用始终从左到右求值。

    您缺少15.7下的文本:

    Java编程语言保证运算符的操作数按特定的求值顺序求值,即从左到右

    表达式的操作数值在表达式本身之前求值。在您的特定情况下,最外层的表达式是
    f1()+[f2()*f3()]
    。我们必须首先计算
    f1()
    ,然后计算
    f2()*f3()
    。其中,首先计算f2(),然后计算f3(),然后计算乘法(它返回
    +
    的操作数的值)。

    Java编程语言保证 运算符(除了条件运算符
    &&
    |
    )显示为 在操作本身的任何部分完成之前,必须进行全面评估 表演

    因此,首先计算
    f1()
    f2()
    f3()
    。然后,应用运算符优先级

    毕竟,您可以观察字节码中的执行顺序,在我的例子中是:

    [...]
    INVOKESTATIC Main.f1 ()I
    INVOKESTATIC Main.f2 ()I
    INVOKESTATIC Main.f3 ()I
    IMUL
    IADD
    
    下面是表达式树的外观:

       +
      / \
     /   \
    f1    *
         / \
        /   \
       f2   f3
    
    首先计算叶,并在树本身中编码运算符优先级

    因为乘法应该在加法之前计算

    正如你所说,这不是乘法优先于加法的合理描述,也不是第15.7.3节的效果。我说你的表情

    评估结果与相同

    f1() + (f2() * f3())
    
    (f1() + f2()) * f3()
    
    ,而不是与

    f1() + (f2() * f3())
    
    (f1() + f2()) * f3()
    
    无论操作数的性质如何,优先级都不能说明首先计算
    +
    运算符的哪个操作数。它表示每个操作数是什么。这确实会影响求值顺序,因为根据优先级规则,原始表达式中的乘法结果必须在加法结果之前进行计算,但这并不能直接说明两个因子的值何时相对于彼此或相对于其他子表达式求值的问题

    与您引用的规则不同的规则负责对
    +
    *
    运算符的两个操作数求值的顺序—始终是左操作数第一,右操作数第二

    在本例中,运算符优先级到底是如何得到尊重的

    该示例的输出没有传递有关优先级(正确理解)是否得到尊重的信息。对于上面两个括号内的备选方案,可以观察到相同的输出,优先顺序是这两个方案中的哪一个与原始表达式等效

    从运算顺序的意义上讲,优先级表示(仅)加法的右操作数是
    f2()*f3()
    ,这意味着必须先计算乘积,然后才能计算出总和。JLS 15.7.3所说的与此无关或不同。该子表达式是乘法并不影响其相对于加法运算的其他操作数的求值顺序

    我知道JLS保证二进制运算的操作数从左到右求值。但是在我的例子中,是为了 理解方法调用顺序有必要理解 考虑哪一个操作(及其两个操作数!) 首先。我错了吗?为什么

    是的,你错了,尽管有JLS,你的例子为这一点提供了很好的证据

    问题似乎是“及其两个操作数分别”位。您的想法似乎大致是Java应该查看表达式,找到所有的乘法运算并对它们进行完整的求值,包括它们的操作数,然后返回并对加法运算执行相同的操作。但这并不需要遵守优先级,它与加法运算从左到右的求值顺序也不一致,这将使Java代码更难编写或读取

    让我们考虑一下你的更长的例子:<