web-dev-qa-db-ja.com

a =(a ++)*(a ++)は、Java

私は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);
45
Marius

最初のa++aは4になります。つまり、3 * 4 = 12になります。

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

110
Bozho

あなたの声明:

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

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

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

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

31
Rok Kralj

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

(a++) * (a++)

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

だからこれは

a = 3 * 4

これは12に相当します。

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

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

+=
  a
  *
    a++
    a++

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

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

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

これはにつながります:

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

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

9
CodesInChaos

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

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

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

3 * 4 = 12 
7
Kal

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

7
Toast

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

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

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行で3つ以上の操作を実行したくないことがすぐに明らかになります。

5
zzzzBov

の場合には :

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

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

5
techExplorer

(a++)は、aを返し、インクリメントすることを意味します。したがって、(a++) * (a++)は3 * 4を意味します

3
lukastymo

これが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]

多田!

3
pablosaraiva

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

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

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

2
Mister Smith

例1

int a = 3;

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

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

例2

int a = 3;

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

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

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

1
Tarik

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

次の質問の場合、答えはカジュアルな観察者には完全に明白です。

17

1
Zeke Hansell

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

a = 3 * (3 + 1) = 3 * 4 = 12
0
Tessmore

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

0
Ranga