表达式与运算符优先级的从左到右的评估。为什么从左到右的评估似乎胜出了?

时间:2017-03-14 17:43:51

标签: java

考虑以下代码:

public class Incrdecr {

static int x = 3;
static int y = ++x * 5 / x-- + --x;

public static void main(String[] args){

    System.out.println("x is " + x);
    System.out.println("y is " + y);
}

评估如下:

x is 2
y is 7

这很有道理,但让我们快速查看运算符优先级表:

enter image description here

据此,应该首先评估后缀运算符。现在,如果我们回到我们的代码,我们会看到x--应该先评估,但它不是。我不记得什么?

换句话说,如果我们严格遵循运算符优先级表,那么表达式将计算为:

y = ++x * 5 / 3 + --x;

当然,它为y提供了完全不同的结果。

2 个答案:

答案 0 :(得分:5)

你的表达从左到右评估是正确的。这是Java中的一般评估顺序(可能有例外)。

我认为你已经弄清楚到底发生了什么:

  1. x从3增加到4,其新值4采用
  2. 5评估为5
  3. 4 * 5 = 20
  4. x,4的值用于划分;除法得到5,x递减到3。
  5. x在最终添加值之前进一步递减到2,然后产生7。
  6. 除外:只有在可以保证结果相同的情况下,才允许编译器交换步骤。因此我们知道结果只能是7。

    尝试将两个概念区分开来:评估顺序和运算符优先级。它们不一样。

    优先级表告诉您表达式被理解为((++x) * 5 / (x--)) + (--x)(这大部分都是好的,因为++(x * 5 / x)-- + --x无论如何都没有意义。)

    举一个不同的例子:f(x) - g(x) * h(x)。 mehtod从左到右调用:f(),然后是g()h()。优先表仅告诉您乘法在减法之前完成。

    编辑:Lew Bloch在评论中质疑x在计算过程中的任何时候都会被评估为4。为了测试这个,我从问题中提出了以下程序变体:

    public class Incrdecr {
    
        static int x = 3;
        static int y = p(++x) * 5 / p(x--) + p(--x);
    
        private static int p(int i) {
            System.out.println("p(): " + i);
            return i;
        }
    
        public static void main(String[] args) {
            System.out.println("x is " + x);
            System.out.println("y is " + y);
        }
    }
    

    打印:

    p(): 4
    p(): 4
    p(): 2
    x is 2
    y is 7
    

    所以是的,在两点x评估为4。

答案 1 :(得分:2)

{{3}}

后递增/递减遵循运算符的从左到右的关联性。

预增量/减量遵循运算符从右到左的关联性。

也就是说: static int y = ++ x * 5 / x-- + --x;

(x--)存储为x(3)的当前值,然后评估其余值。

++ x被评估为x =(x + 1)强制评估后增量,因为它是一个赋值,因此它变为(3)然后--x被计算为x =(x-1)或2。

这在功能上是等效的: y =(x = x + 1)* 5 / x-- +(x = x-1)(它将在您的Java代码中以这样的方式运行)

得到的等式是:

3 * 5/3 + 2。