简体   繁体   English

分配一个变量,实际发生了什么,Java

[英]Assigning a variable, what actually happens, Java

In the following example what actually happens? 在下面的例子中实际发生了什么?

int a = 1;
a += (a = 2);

The output is 3, however I wanted to know what actually happens under the covers. 输出是3,但我想知道封面下究竟发生了什么。 For example i know that parentheses have higher priority to + so happening first (a = 2) the expression should become a = 2 + 2 . 例如,我知道括号的优先级高于+所以首先发生(a = 2)表达式应该变为a = 2 + 2 At runtime first the expression within parentheses should be executed and then a becomes 2. It seems that the first a on the left to + gets "loaded" before of (a = 2) and this last expression does not seem to override the previous loading. 在运行时会首先括号内的表达式应该被执行,然后变成2.看来,第一次a在左边+被“装”的前(a = 2)这最后的表达似乎并没有覆盖以前装载。 In other words I am quite confused to what exactly happens behind the scenes. 换句话说,我对幕后究竟发生了什么感到困惑。

If anybody knows, thanks a lot in advance. 如果有人知道,请提前多多感谢。

From the JLS section §15.26.2 Compound Assignment Operators : 来自JLS 部分§15.26.2复合赋值运算符

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once. 形式E1 op = E2的复合赋值表达式等效于E1 =(T)((E1)op(E2)),其中T是E1的类型,除了E1仅被评估一次。

So for your example we have: 因此,对于您的示例,我们有:

a = (a) + (a = 2)

With the expression evaluated left to right. 表达式从左到右评估。 Hence the output of 3 因此输出3

See the referenced example 15.7.1-2 from http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.1 , which is almost identical to the example you provided. 请参阅http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.1中引用的示例15.7.1-2 ,这与您的示例几乎相同提供。 In particular: 特别是:

If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation. 如果运算符是复合赋值运算符(第15.26.2节),则对左侧操作数的计算包括记住左侧操作数表示的变量并获取并保存该变量的值以用于隐含的二进制操作。

Because of this precedence, the left hand of the += is evaluated first. 由于这个优先级,首先评估+ =的左手。

It might be confusing to you because of the parentheses, but note the section on parenthesis evaluation: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.3 , and in particular: 由于括号,您可能会感到困惑,但请注意括号评估部分: http//docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.3 ,特别是:

The Java programming language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence. Java编程语言遵循由括号显式指示的评估顺序,并且隐含地由运算符优先级指示。

In this case, the implicit precedence set by the += operator indicates that the left hand operand will be remembered per the spec. 在这种情况下,+ =运算符设置的隐式优先级表示将根据规范记住左侧操作数。 While it's true that assignment operators, including "+=" have lowest precedence, the spec for += indicates that the left-hand operand will be remembered per 15.26.2. 虽然包括“+ =”在内的赋值运算符具有最低优先级,但+ =的规范表示将按15.26.2记住左侧操作数。

Let's take a look at the bytecode of the following program: 我们来看看以下程序的字节码:

package A;

public class Test
{
    public static void main(String[] args)
    {
        int a = 1;
        a += (a = 2);
    }
}

We just need to run this command: 我们只需要运行这个命令:

javap -c Test.class

to get the following bytecode: 获取以下字节码:

public class A.Test {
  public A.Test();
    Code:
       0: aload_0
       1: invokespecial #1           // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: istore_1
       2: iload_1
       3: iconst_2
       4: dup
       5: istore_1
       6: iadd
       7: istore_1
       8: return
}

Explanation: 说明:

We will just focus on the two lines inside the main method: 我们将只关注main方法中的两行:

int a = 1;
a += (a = 2);

[ int a = 1; [ int a = 1; begins here] 从这里开始]

0: iconst_1
  • Pushes int 1 onto the stack. 将int 1推入堆栈。
-------------
|           |
-------------
|           |
-------------
|     1     |
-------------
    STACK

1: istore_1
  • Pops int value from the stack to variable 1 ( variable 1 represents a ) 从堆栈弹出int值到variable 1variable 1表示a
-------------
|           |             variable 1
-------------           --------------
|           |           |     1      |
-------------           --------------
|           |
-------------
    STACK

[ int a = 1; [ int a = 1; finishes here] 在这里完成]


[ a += (a = 2); [ a += (a = 2); begins here] 从这里开始]

2: iload_1
  • Loads an int value from local variable 1 and pushes it onto the stack. 从局部variable 1加载一个int值并将其推送到堆栈。
-------------
|           |             variable 1
-------------           --------------
|           |           |            |
-------------           --------------
|     1     |
-------------
    STACK

3: iconst_2
  • Pushes int 2 onto the stack. 将int 2推入堆栈。
-------------
|           |             variable 1
-------------           --------------
|     2     |           |            |
-------------           --------------
|     1     |
-------------
    STACK

4: dup
  • duplicate the value on top of the stack. 复制堆栈顶部的值。
-------------
|     2     |             variable 1
-------------           --------------
|     2     |           |            |
-------------           --------------
|     1     |
-------------
    STACK

5: istore_1
  • Pops int value from the stack to variable 1 . 将int值从堆栈弹出到variable 1
-------------
|           |             variable 1
-------------           --------------
|     2     |           |      2     |
-------------           --------------
|     1     |
-------------
    STACK

6: iadd
  • Adds the top two values together. 将前两个值一起添加。
-------------
|           |             variable 1
-------------           --------------
|           |           |      2     |
-------------           --------------
|     3     |
-------------
    STACK

7: istore_1
  • Pops int value from the stack to variable 1 . 将int值从堆栈弹出到variable 1
-------------
|           |             variable 1
-------------           --------------
|           |           |      3     |
-------------           --------------
|           |
-------------
    STACK

[ a += (a = 2); [ a += (a = 2); finishes here] 在这里完成]


8: return
  • The main method returns. 主要方法返回。

Conclusion: 结论:

a = a + (a = 2) is done through several operations. a = a + (a = 2)通过几次操作完成。 2: iload_1 is executed as first command of a += (a = 2); 2: iload_1执行2: iload_1作为a += (a = 2);第一个命令a += (a = 2); which reads the first operand of the equation a = a + (a = 2) and pushes onto the stack. 它读取等式a = a + (a = 2)的第一个操作数并推入堆栈。

Next, 3: iconst_2 and 4: dup are executed which basically push int 2 twice onto the stack; 接下来,执行3: iconst_24: dup ,基本上将int 2两次推入堆栈; one for loading it to a and the other as the second operand. 一个用于将其加载到a ,另一个用作第二个操作数。 After that, 5: istore_1 is executed which is loading 2 into a ( a = 2 ). 之后,执行5: istore_1 ,其将2加载到aa = 2 )中。

Finally, 6: iadd and 7: istore_1 are executed where 6: iadd adds the first operand and the second operand and pushes the result onto the stack, and 7: istore_1 pops the result and loads it into a . 最后, 6: iadd7: istore_1被执行,其中6: iadd添加第一个操作数和第二个操作数并将结果推送到堆栈上, 7: istore_1弹出结果并将其加载到a


For simplicity, let's have a quick look at this code: 为简单起见,我们快速浏览一下这段代码:

int a = 1;
int b = 3;
a += b;

and here is its bytecode: 这是它的字节码:

public class A.Test {
  public A.Test();
    Code:
       0: aload_0
       1: invokespecial #1            // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_3
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: istore_1
       8: return
}

As you can see, it simply does the following: 如您所见,它只是执行以下操作:

  • Loads int 1 into a . 将int 1加载到a
  • Loads int 3 into b . 将int 3加载到b
  • Pushes a then b onto the stack. a然后b推到堆栈上。
  • Performs the addition on them and pushes the result onto the stack. 对它们执行添加并将结果推送到堆栈。
  • Pops the result from the stack and stores it into a . 从栈中弹出结果,并将其存储到a

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM