45

私はOCPJP試験の勉強をしているので、Javaの少し奇妙な詳細をすべて理解する必要があります。これには、インクリメント前およびインクリメント後の演算子が変数に適用される順序が含まれます。次のコードは私に奇妙な結果を与えています:

int a = 3;

a = (a++) * (a++);

System.out.println(a); // 12

答えは11ではないですか?または多分13?しかし、12ではありません!

ファローアップ:

次のコードの結果は何ですか?

int a = 3;

a += (a++) * (a++);

System.out.println(a);
4

15 に答える 15

110

最初が4になったa++ a。だからあなたは3 * 4 = 12

a2番目以降は5になりますが、割り当てがオーバーライドされるa++ため、これは破棄されます)a =

于 2011-11-07T16:02:49.387 に答える
31

あなたの声明:

a += (a++) * (a++);

それらのいずれかと同等です:

a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)

代わりにそれらのいずれかを使用してください。

于 2011-11-07T16:02:26.847 に答える
25

a++'aの値を意味し、aは1ずつ増加します'。だからあなたが走るとき

(a++) * (a++)

最初a++の値が最初に評価され、値3aが生成されます。次に1ずつインクリメントされます。次に2番目の値a++が評価されます。a値4を生成し、その後再びインクリメントされます(ただし、これは今は問題ではありません)

だからこれはになります

a = 3 * 4

これは12に相当します。

于 2011-11-07T16:04:02.083 に答える
9
int a = 3;
a += (a++) * (a++);

最初に構文ツリーを構築します。

+=
  a
  *
    a++
    a++

それを評価するには、最も外側の要素から始めて、再帰的に降下します。各要素について、次のことを行います。

  • 左から右に子供を評価する
  • 要素自体を評価する

演算子は特別です。それはの+=ようなものに拡張されますがleft = left + right、式を評価するのはleft1回だけです。それでも、右側が値に評価される前に、左側が(変数だけでなく)値に評価されます。

これはにつながります:

  1. 評価を開始します+=
  2. 変数への代入の左側を評価しますa
  3. a変数を、加算で使用される値に評価します3
  4. 評価を開始します*
  5. 最初のを評価しa++ます。これにより、aの現在の値が返され、次のよう3に設定aされます。4
  6. 2番目を評価しa++ます。これにより、aの現在の値が返され、次のよう4に設定aされます。5
  7. 積を計算します:3 * 4 = 12
  8. 実行し+=ます。左側3は3番目のステップで評価され、右側は12です。したがって、3 + 12=15をに割り当てaます。
  9. の最終値aは15です。

ここで注意すべきことの1つは、演算子の優先順位が評価の順序に直接影響しないことです。それは木の形にのみ影響し、したがって間接的に順序に影響します。ただし、ツリー内の兄弟の間では、演算子の優先順位に関係なく、評価は常に左から右になります。

于 2011-11-08T11:20:19.230 に答える
7

(a++)はポストインクリメントであるため、式の値は3です。

(a++)はポストインクリメントなので、式の値は4になります。

式の評価は左から右に行われています。

3 * 4 = 12 
于 2011-11-07T16:03:13.603 に答える
7

a ++を使用するたびに、aをポストインクリメントします。つまり、最初のa ++は3と評価され、2番目は4と評価されます。3* 4=12。

于 2011-11-07T16:03:22.400 に答える
5

オペレーターがどのように機能するかについては、一般的に理解が不足しています。正直なところ、すべての演算子は糖衣構文です。

あなたがしなければならないのは、すべてのオペレーターの背後で実際に何が起こっているのかを理解することです。次のように想定します。

a = b -> Operators.set(a, b) //don't forget this returns b
a + b -> Operators.add(a, b)
a - b -> Operators.subtract(a, b)
a * b -> Operators.multiply(a, b)
a / b -> Operators.divide(a, b)

次に、これらの一般化を使用して複合演算子を書き直すことができます(簡単にするために戻り型は無視してください)。

Operators.addTo(a, b) { //a += b
  return Operators.set(a, Operators.add(a, b));
}

Operators.preIncrement(a) { //++a
  return Operators.addTo(a, 1);
}

Operators.postIncrement(a) { //a++
  Operators.set(b, a);
  Operators.addTo(a, 1);
  return b;
}

あなたはあなたの例を書き直すことができます:

int a = 3;
a = (a++) * (a++);

なので

Operators.set(a, 3)
Operators.set(a, Operators.multiply(Operators.postIncrement(a), Operators.postIncrement(a)));

これは、複数の変数を使用して分割できます。

Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))

その方が確かに冗長ですが、1行で2つ以上の操作を実行したくないことがすぐに明らかになります。

于 2011-11-07T19:05:22.257 に答える
5

の場合には :

int a = 3;  
a = (a++) * (a++); 

a = 3 * a++; now a is 4 because of post increment
a = 3 * 4; now a is 5 because of second post increment
a = 12; value of 5 is overwritten with 3*4 i.e. 12 

したがって、出力は12として取得されます。

の場合には :

a += (a++) * (a++); 
a = a + (a++) * (a++);
a = 3 + (a++) * (a++); // a is 3
a = 3 + 3 * (a++); //a is 4
a = 3 + 3 * 4; //a is 5
a = 15

ここで注意すべき主な点は、この場合、コンパイラは左から右に解決し、ポストインクリメントの場合、インクリメント前の値が計算に使用され、左から右に移動するときにインクリメントされた値が使用されることです。

于 2011-11-09T06:06:06.450 に答える
3

(a++)リターンaとインクリメントを (a++) * (a++)意味するので、3*4を意味します

于 2011-11-07T16:05:34.863 に答える
3

これがJavaコードです:

int a = 3;
a = (a++)*(a++);

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

  0  iconst_3
  1  istore_1 [a]
  2  iload_1 [a]
  3  iinc 1 1 [a]
  6  iload_1 [a]
  7  iinc 1 1 [a]
 10  imul
 11  istore_1 [a]

これが何が起こるかです:

3をスタックにプッシュし、スタックから3をポップして、に格納します。これでa=3になり、スタックは空になります。

  0  iconst_3
  1  istore_1 a

ここで、値を「a」(3)からスタックにプッシュしてから、a(3-> 4)をインクリメントします。

  2  iload_1 [a]
  3  iinc 1 1 [a]

したがって、「a」は「4」に等しく、スタックは{3}に等しくなります。

次に、「a」を再度ロードし(4)、スタックにプッシュして「a」をインクリメントします。

  6  iload_1 [a]
  7  iinc 1 1 [a]

これで、「a」は5に等しく、スタックは{4,3}に等しくなります。

したがって、最終的にスタックから最初の2つの値(4と3)をポップし、乗算してスタックに戻します(12)。

 10  imul

ここで、「a」は5に等しく、スタックは12に等しくなります。

最後に、スタックからポップ12があり、に格納されます。

 11  istore_1 [a]

多田!

于 2011-11-08T18:39:03.983 に答える
2

12です。式は左から評価を開始します。だからそれはします:

a = (3++) * (4++);

最初の部分(3 ++)が評価されると、aは4になるため、次の部分ではa = 3 * 4 = 12になります。最後のポストインクリメント(4 ++)は実行されますが、効果はありません。この後、aに値12が割り当てられるためです。

于 2011-11-07T16:07:11.473 に答える
1

例1

int a = 3;

a = (++a) * (a++);

System.out.println(a); // 16

例2

int a = 3;

a = (++a) * (++a);

System.out.println(a); // 20

++場所に基づいて値を変更する式をどこに配置するかを確認するだけです。

于 2011-11-08T17:09:50.100 に答える
1

誰もが最初の式と、aの値が12である理由を明確に説明しています。

次の質問の場合、答えはカジュアルなオブザーバーには完全に明白です。

17

于 2011-11-08T21:27:47.310 に答える
0

次回使用するときにa++を使用すると、1ずつ増加します。だからあなたは

a = 3 * (3 + 1) = 3 * 4 = 12
于 2011-11-07T16:03:53.757 に答える
0

プレフィックスの前後の増分は、乗算演算子よりも優先されます。したがって、式は3*4として評価されます。

于 2011-11-07T16:08:18.877 に答える