8

次の例では、実際に何が起こるでしょうか?

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

出力は 3 ですが、裏で実際に何が起こっているのか知りたいと思っていました。たとえば、括弧の優先度が高いことを知っている+ため、最初に発生する (a = 2) 式は になりa = 2 + 2ます。実行時に、最初に括弧内の式を実行する必要があり、次に a が 2 になります。a左側の最初の式が+of の前に「ロード」され(a = 2)、この最後の式が前のロードをオーバーライドしていないようです。言い換えれば、舞台裏で正確に何が起こっているのか、私はかなり混乱しています。

どなたかご存知でしたら、よろしくお願いします。

4

3 に答える 3

4

JLSセクション§15.26.2複合代入演算子から:

E1 op = E2の形式の複合代入式は、E1 =(T)((E1)op(E2))と同等です。ここで、TはE1のタイプですが、E1は1回だけ評価されます。

したがって、あなたの例では、次のようになります。

a = (a) + (a = 2)

式を左から右に評価します。したがって、3の出力

于 2013-03-08T21:12:14.663 に答える
2

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.1の参照例15.7.1-2を参照してください。これは、作成した例とほぼ同じです。提供された。特に:

演算子が複合代入演算子 (§15.26.2) である場合、左側のオペランドの評価には、左側のオペランドが示す変数の記憶と、暗黙の 2 項演算で使用するためのその変数の値のフェッチと保存の両方が含まれます。 .

この優先順位のため、+= の左側が最初に評価されます。

括弧のために混乱するかもしれませんが、括弧の評価に関するセクションに注意してください: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.3、特に:

Java プログラミング言語は、括弧で明示的に示される評価の順序と、演算子の優先順位によって暗黙的に示される評価の順序を尊重します。

この場合、+= 演算子によって設定される暗黙の優先順位は、左側のオペランドが仕様に従って記憶されることを示します。「+=」を含む代入演算子の優先順位が最も低いのは事実ですが、+= の仕様は、左側のオペランドが 15.26.2 に従って記憶されることを示しています。

于 2013-03-08T21:21:56.877 に答える
2

次のプログラムのバイトコードを見てみましょう。

package A;

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

次のコマンドを実行するだけです。

javap -c Test.class

次のバイトコードを取得します。

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
}

説明:

main メソッド内の 2 行だけに注目します。

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

int a = 1;ここから始まる】

0: iconst_1
  • int1をスタックにプッシュします。
-------------
|           |
-------------
|           |
-------------
|     1     |
-------------
    STACK

1: istore_1
  • スタックから int 値をvariable 1(variable 1を表すa)にポップします。
-------------
|           |             variable 1
-------------           --------------
|           |           |     1      |
-------------           --------------
|           |
-------------
    STACK

int a = 1;ここまでです】


a += (a = 2);ここから始まる】

2: iload_1
  • ローカルから int 値をロードvariable 1し、スタックにプッシュします。
-------------
|           |             variable 1
-------------           --------------
|           |           |            |
-------------           --------------
|     1     |
-------------
    STACK

3: iconst_2
  • int2をスタックにプッシュします。
-------------
|           |             variable 1
-------------           --------------
|     2     |           |            |
-------------           --------------
|     1     |
-------------
    STACK

4: dup
  • スタックの一番上に値を複製します。
-------------
|     2     |             variable 1
-------------           --------------
|     2     |           |            |
-------------           --------------
|     1     |
-------------
    STACK

5: istore_1
  • int 値をスタックから にポップしますvariable 1
-------------
|           |             variable 1
-------------           --------------
|     2     |           |      2     |
-------------           --------------
|     1     |
-------------
    STACK

6: iadd
  • 上位 2 つの値を加算します。
-------------
|           |             variable 1
-------------           --------------
|           |           |      2     |
-------------           --------------
|     3     |
-------------
    STACK

7: istore_1
  • int 値をスタックから にポップしますvariable 1
-------------
|           |             variable 1
-------------           --------------
|           |           |      3     |
-------------           --------------
|           |
-------------
    STACK

a += (a = 2);ここまでです】


8: return
  • メイン メソッドが戻ります。

結論:

a = a + (a = 2)いくつかの操作によって行われます。式の最初のオペランドを読み取り、スタックにプッシュする2: iload_1最初のコマンドとして実行されます。a += (a = 2);a = a + (a = 2)

次に、基本的に intを 2 回スタックにプッシュする3: iconst_2andが実行されます。1 つはそれをロードするためのもので、もう 1 つは 2 番目のオペランドとしてのものです。その後、( ) にロードするが実行されます。4: dup2a5: istore_12aa = 2

最後に、6: iadd第1 オペランドと第 2 オペランドを加算して結果をスタックにプッシュし、結果をポップして にロードする7: istore_1場所で実行されます。6: iadd7: istore_1a


簡単にするために、このコードを簡単に見てみましょう。

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

バイトコードは次のとおりです。

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
}

ご覧のとおり、次のことを行うだけです。

  • にint1をロードしaます。
  • にint3をロードしbます。
  • aその後、スタックにプッシュbします。
  • それらに対して加算を実行し、結果をスタックにプッシュします。
  • スタックから結果をポップし、 に格納しaます。
于 2013-03-08T22:42:04.577 に答える