何时在表达式中评估/返回/获取Java变量中的值?

时间:2016-10-07 20:53:49

标签: java increment

根据http://introcs.cs.princeton.edu/java/11precedence/,后增量运算符的优先级高于加法运算符。

因此,对于以下代码:

    int i = 1;
    int j = i + i++;
    System.out.println(j);

我原本以为分配给j的表达式将按如下方式进行评估(评估中每行为"步骤")

   i + i++
   i + (1)   // do post-increment operator; returns 1, and makes i = 2
   (2) + (1)   // do addition operator. need to get the operand i, so do that.
   3

但是当我尝试这个程序时,j的值是2 所以我很困惑。在表达式中,它是否用i的当前值替换表达式中的所有" i,甚至在触及i ++之前?

编辑:短语"评估顺序"这里的人使用,帮助我找到以下可能有用的stackoverflow答案:What are the rules for evaluation order in Java?

编辑:我在下面的答案中做了最好的猜测。我仍然欢迎对它进行更正。

4 个答案:

答案 0 :(得分:2)

根据Java Language Specification, 15.7.1

  

在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已完全评估。

因此,在右侧i之前评估加法运算符左侧的i++

答案 1 :(得分:0)

增量后 - 首先使用先前的变量值然后递增 预增量 - 首先增量,然后使用新的变量值。

+

这里首先用前面的i值i替换i,e 1再次int i = 1; int j = i++ + ++i; System.out.println(j);// 4 System.out.println(i);// 3 的旧值,所以j将变为2,然后i增加到2。

现在考虑一下这段代码

{{1}}

这里首先i增加(pre),所以我变成2然后我被替换i,ej = 2 + 2,现在j值将是4并且再次i增加(post)一个所以我这样做当前值为3。

答案 2 :(得分:0)

不要让自己被"优先级"误导。字。 本教程的主要内容是,在解析表达式方面,后增量运算符的绑定比加法更强。

如果我们明确括号,示例中的表达式将显示为(i + (i++)),而不是((i + i)++)。 这是什么优先级意味着:没有明确的括号,将它们隐含地放在后增量之前,然后围绕加法。

当表达式的组件成功分组后,将考虑评估规则。在这种情况下,正如Korolar指出的那样,JLS 15.7.1是要考虑的段落,(简单地说)指示了对加法运算的从左到右的评估。

答案 3 :(得分:0)

编辑:我不理解其他人完全给出的答案,但这是我对正在发生的事情的最好猜测。如果有人想纠正这个猜测,请这样做。

我最好的猜测: {(1}},其中a,b和c是变量,被制作成表达式树,其中优先级最低的运算符位于树的顶部:

a + b * c

现在,这个树的评估如下:+运算符得到评估。为此,它(递归地)评估左子树及其右子树,然后添加这些值。

完整的,这就是:

    +
  /   \
 a     *
      / \
     b    c

这就是 - addition operator gets evaluated. it says "evaluate my left subtree, then my right subtree, then add them together. i return that value" - left subtree: is a. evaluate variable a into a value. (that is, get the value of variable a.) - right subtree: i'm a multiplication operator. to evaluate me, evaluate my left subtree, then my right subtree, the nmultiply them togeter. i return that value. - left subtree: is variable b. evalute that. - right subtree: is variable c. evaluate that. 首先完成评估,然后是a,然后是b,然后是c,然后是b * c

的原因

在带有++ i东西的表达式中,同样的事情发生了。例如,对于a + (b * c),表达式树将如下所示:

++i + i++

其中(例如)preinc表示preincrement运算符(而preincrement运算符只取一个操作数:变量)。这里的区别在于,当需要对preinc作为其根的子树进行求值时,“评估preinc运算符树”并不意味着“用变量的值替换操作数中的变量”(它的方式)例如,2 + i),但它意味着“增加变量i中的值,然后preinc(i)的值是变量i中的新值。”

以类似的方式,赋值运算符=的工作方式与2 + i略有不同。

          +
         / \
    preinc  postinc
       |      |  
       i      i

这里的表达式树是

    int j;
    j = 3;

当需要对赋值运算符作为其根的树进行求值时,这意味着“左手操作符必须是变量 - 而不是值!然后评估正确的子树(我们希望它将它评估为value),然后将值放在右子树中左子树中的变量中。现在,=(j,3)返回的值是右子树中的值“。

有了这个猜测,我能够正确地为评估顺序的Java语言规范中的示例提供答案(链接是:https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7)。

也就是说,如果我绘制表达式树,我可以解决以下两个例子:
例如:

        =
       / \
      j   3

示例:

  int i = 2;
  int j = (i = 3) * i;
  System.out.println(j);