Java表达式计算优先级:方法调用&;数组索引

Java表达式计算优先级:方法调用&;数组索引,java,operators,operator-precedence,associativity,Java,Operators,Operator Precedence,Associativity,在研究java表达式计算顺序的过程中,我遇到了一个我无法向自己解释清楚的现象。有两个问答题。它被要求定义控制台输出 示例1 int[] a = {5, 5}; int b = 1; a[b] = b = 0; System.out.println(Arrays.toString(a)); 正确的控制台输出为:[5,0] 示例2 public class MainClass { static int f1(int i) { System.out.print(i + ",

在研究java表达式计算顺序的过程中,我遇到了一个我无法向自己解释清楚的现象。有两个问答题。它被要求定义控制台输出

示例1

int[] a = {5, 5};
int b = 1;
a[b] = b = 0;
System.out.println(Arrays.toString(a));
正确的控制台输出为:
[5,0]

示例2

public class MainClass {

    static int f1(int i) {
        System.out.print(i + ",");
        return 0;
    }

    public static void main(String[] args) {
        int i = 0;
        i = i++ + f1(i);
        System.out.print(i);
    }
}
正确的控制台输出为:
1,0

据我所知,java中存在具有顺序优先级的操作符组(级别),表达式根据操作符优先级进行计算。此外,每个组都有关联性,如果运算符具有相同的优先级,则将按照组关联性指定的顺序对其求值。运算符优先级表(来自Cay S.Horstmann-Core Java V.1):

#算子结合性 1 [] . ()从左到右的方法调用 2 ! ~ ++ -- + - (类型)从右向左铸造新的 3*/%从左到右 4+-从左到右 ... 14=+=-=其余部分从右到左省略 通过上表可以清楚地看出,在示例1中,具有最高优先级的运算符是数组索引
a[b]
,然后从右到左计算分配运算符:
b=0
,然后
a[1]=0
。这就是为什么
a=[5,0]

但是例子2让我很困惑。根据优先级表,具有最高优先级的操作符是
f1(i)
方法调用(应打印
0
),然后是一元后增量
i++
(使用当前
i=0
并在之后递增),然后是加法操作符
0+0
和аssignment操作符最后
i=0
。因此,我假设正确的输出是
0,0

但事实并非如此。事实上,首先计算一元后增量
i++
(将
i
增加到
1
),然后方法调用
f1(i)
打印
1
,并返回
0
,最后由分配运算符赋值
i=0+0
,所以最后的
i
值是
0
,正确答案是
1,0


我认为这是由于二进制加法运算符“从左到右”的关联性造成的,但在这种情况下,为什么在示例2中首先计算加法,而在示例1中,首先计算最高优先级的运算符
a[b]
?我注意到示例2中的所有操作符都在不同的组中,所以我们根本不应该考虑操作符的关联性,对吗?难道我们不应该对示例2中的所有运算符按优先级排序并按结果顺序求值吗?

运算符的存在相关性和关联性会影响源代码解析为表达式树的方式。但是:任何表达式中的求值顺序仍然是从左到右

这就是为什么在
i+++f1(i)
中,我们首先计算
i++
,然后计算它们的和


具有最高优先级的方法调用意味着
i+++f1(i)
永远不会被解析为
(i+++f1)(i)
(如果这有意义的话),而是始终
i++(f1(i))
。优先级并不意味着“先求值后求值”。

运算符的存在依赖性和关联性会影响源代码解析到表达式树中的方式。但是:任何表达式中的求值顺序仍然是从左到右

这就是为什么在
i+++f1(i)
中,我们首先计算
i++
,然后计算它们的和

具有最高优先级的方法调用意味着
i+++f1(i)
永远不会被解析为
(i+++f1)(i)
(如果这有意义的话),而是始终
i++(f1(i))
。优先级并不意味着“比其他任何东西都要先进行评估。”

您会感到困惑

=
的从右到左关联性意味着

a[b] = b = 0;
被评估为

a[b] = (b = 0);
但是计算仍然是从左到右的,因此在更新
b
的值之前,先计算第一个
b
的值

a[b] = (b = 0)     a = { 5, 5 }, b = 1
// evaluate 'b'
a[1] = (b = 0)     a = { 5, 5 }, b = 1
// evaluate 'b = 0'
a[1] = 0           a = { 5, 5 }, b = 0
// evaluate 'a[1] = 0'
0                  a = { 5, 0 }, b = 0
你把我搞糊涂了

=
的从右到左关联性意味着

a[b] = b = 0;
被评估为

a[b] = (b = 0);
但是计算仍然是从左到右的,因此在更新
b
的值之前,先计算第一个
b
的值

a[b] = (b = 0)     a = { 5, 5 }, b = 1
// evaluate 'b'
a[1] = (b = 0)     a = { 5, 5 }, b = 1
// evaluate 'b = 0'
a[1] = 0           a = { 5, 5 }, b = 0
// evaluate 'a[1] = 0'
0                  a = { 5, 0 }, b = 0

我在这里发布了另一个链接,其中明确描述了评估顺序和优先级的区别(如果其他人需要):我在这里发布了另一个链接,其中明确描述了评估顺序和优先级的区别(如果其他人需要):