18

Java の演算子の優先順位について 2 つの同様の質問があります。

最初の1つ:

int X = 10;
System.out.println(X++ * ++X * X++); //it prints 1440 

Oracle のチュートリアルによると:
後置 (expr++, expr--) 演算子は前置 (++expr, --expr) よりも優先順位が高い

したがって、評価順序は次のようになります。

1) first postfix operator: X++ 
   1.a) X++ "replaced" by 10
   1.b) X incremented by one: 10+1=11
   At this step it should look like:  System.out.println(10 * ++X * X++), X = 11;

2) second POSTfix operator: X++ 
   2.a) X++ "replaced" by 11
   2.b) X incremented by one: 11+1=12
   At this step it should look like:  System.out.println(10 * ++X * 11), X = 12;

3) prefix operator: ++X
   3.a) X incremented by one: 12+1=13
   3.b) ++X "replaced" by 13
   At this step it should look like:  System.out.println(10 * 13 * 11), X = 13;

4) evaluating 10*13 = 130, 130*11 = 1430.

しかし、Java は PRE/POST の順序付けを無視して、それらを 1 つのレベルに置いているようです。したがって、実際の順序は次のとおりです。

 X++ -> ++X -> X++ 

答えが (10 * 12 * 12) = 1440 になる理由.

二つ目:

この質問の例:

    int a=1, b=2;             
    a = b + a++;

受け入れられた回答の一部:「割り当ての時点までに、(優先順位のために) to++の値が既にインクリメントされているため、そのインクリメントされた値を上書きします。」a2=

では、順を追って見ていきましょう。

 1) replacing "b" with 2
 2) replacing "a++" with 1
 3) incrementing "a" by 1 -> at this point a==2
 4) evaluating 2+1 = 3
 5) overwriting incremented value of "a" with 3

すべて問題ないようです。しかし、そのコードを少し変更してみましょう (「=」を「+=」に置き換えます)。

    a += b + a++;

手順 1 ~ 4 は上記と同じです。したがって、ステップ 4 の後は次のようになります。

    a += 3;

どこa==2

そして、私は考えます:OK、a = 2+3そうaあるべきです5。しかし、答えはただ4

私は本当に混乱しています。私はすでに数時間を費やしましたが、どこが間違っているのかまだ理解できません。

PS私は、この「スタイル」を実際のアプリケーションで使用すべきではないことを知っています。自分の考えの何が間違っているのかを理解したいだけです。

4

5 に答える 5

17

混乱は、オペランドが左から右に 評価されるという事実から生じます。これは、演算子の優先順位/操作の順序に注意が払われる前に、最初に行われます

この動作はJLS 15.7.2 で指定されています。演算前にオペランドを評価する

したがってX++ * ++X * X++、最初に評価されるの10 * 12 * 12は、ご覧のように 1440 になります。

これを確信するには、次の点を考慮してください。

X = 10; System.out.println(X++ * ++X);
X = 10; System.out.println(++X * X++);

X++最初に実行され、次に++X2 番目に実行され、次に乗算された場合、両方が同じ数を出力するはずです。

しかし、彼らはしません:

X = 10; System.out.println(X++ * ++X); // 120
X = 10; System.out.println(++X * X++); // 121

それで、これはどのように理にかなっていますか?オペランドが左から右に評価されることを理解すれば、それは完全に理にかなっています。

X = 10; System.out.println(X++ * ++X); // 120 (10 * 12)
X = 10; System.out.println(++X * X++); // 121 (11 * 11)

最初の行は次のようになります

X++       * ++X
10 (X=11) * (X=12) 12
10        * 12 = 120

そして2番目

++X       * X++
(X=11) 11 * 11 (X=12)
11        * 11 = 121

では、なぜ前置および後置のインクリメント/デクリメント演算子が表にあるのでしょうか?

乗算の前にインクリメントとデクリメントを実行する必要があることは事実です。しかし、それが言っていることは次のとおりです。

Y = A * B++

// Should be interpreted as
Y = A * (B++)

// and not
Y = (A * B)++

同じように

Y = A + B * C

// Should be interpreted as
Y = A + (B * C)

// and not
Y = (A + B) * C

オペランドの評価の順序が左から右に発生することに変わりはありません。


それでも確信が持てない場合:

次のプログラムを検討してください。

class Test
{
    public static int a(){ System.out.println("a"); return 2; }
    public static int b(){ System.out.println("b"); return 3; }
    public static int c(){ System.out.println("c"); return 4; }

    public static void main(String[] args)
    {
        System.out.println(a() + b() * c());
        // Lets make it even more explicit
        System.out.println(a() + (b() * c()));
    }
}

引数が必要なときに評価さbれた場合、 or のいずれかcが最初に来て、もう一方が次に来て、最後にa. ただし、プログラムは次のように出力します。

a
b
c
14
a
b
c
14

式で必要とされ、使用される順序に関係なく、左から右に評価されるためです。

役に立つ読み物:

于 2013-09-24T21:04:09.930 に答える
1

その1440の理由は

  1. x は 10 に設定されます。つまり、第 1 項は FIXED です (全体の式 10 *)

  2. x は 1 ずつインクリメントされ、x =11 になりました

  3. x は事前に 1 ずつインクリメントされます x=12 であり、第 2 項は現在修正されています (全体の式 10 * 12 *)

  4. 現在、x は 12 に設定され、第 3 項は FIXED (全体の式 10 * 12 *12) に設定されています。

  5. x は増分ですが、この場合は評価には使用されません。

要するに、この場合はXである変数が発生すると、用語は修正されます

2番目のケース:よくわかりませんが、次のように壊れる可能性があると思います。

  1. a=b+a
  2. a++

それが起こっていると思います。

于 2013-09-24T20:41:40.147 に答える
0

最初の一歩

1) first postfix operator: X++ 
   1.a) X++ "replaced" by 10
   1.b) X incremented by one: 10+1=11
   At this step it should look like:  System.out.println(10 * ++X * X++), X = 11;

2) prefix operator: ++X
   2.a) X "replaced" by 11
   2.b) X incremented by one: 11+1=12
   At this step it should look like:  System.out.println(10 * 12 * X++), X = 12;

3) second POSTfix operator: X++
   3.a) X "replaced" by 12
   3.b) X incremented by one: 12+1=13
   At this step it should look like:  System.out.println(10 * 12 * 12),  X = 13;

これは印刷します10 * 12 * 12 = 1440

これは最初のステップのバイトコードです

 1. bipush 10
 2. istore_0
 3. getstatic java/lang/System/out Ljava/io/PrintStream;
 4. iload_0
 5. iinc 0 1
 6. iinc 0 1
 7. iload_0
 8. imul
 9. iload_0
10. iinc 0 1
11. imul
12. invokevirtual java/io/PrintStream/println(I)V
13. return

これは、次のことを行います。

 1. Push 10 to the stack
 2. Pop 10 from the stack to X variable
 3. Push X variable value (10) to the stack
 5. Increment local variable X (11)
 6. Increment local variable X (12)
 7. Push X variable value (12) to the stack
 8. Multiply top and subtop (10*12) Now Top = 120 
 9. Push X variable value (12) to the stack
10. Increment local variable X (13)
11. Multiply top and subtop (120*12) Now Top = 1440

X をスタックにプッシュした後、最後のインクリメント (10.) が行われることに注意してください。

于 2013-09-24T20:33:40.980 に答える