11

XOR 演算子を使用して、Java で 2 つの整数変数の値を交換したいと考えています。

これは私のコードです:

int i = 24;
int j = 17;

i ^= j;
j ^= i;
i ^= j;

System.out.println("i : " + i + "\t j : " + j);

正常に機能しますが、次の同等のコードは機能しません。

int i = 24;
int j = 17;

i ^= j ^= i ^= j;

System.out.println("i : " + i + "\t j : " + j);

出力は次のようになります。

i : 0    j : 24

最初の変数はゼロです! Javaの何が問題になっていますか?

4

5 に答える 5

10

Java 仕様(Java 7 仕様) によると、セクション 15.26.2 (529 ページ)。

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

セクション 15.7 評価順序(ページ 423)によると(強調鉱山):

15.7 評価順序

Java プログラミング言語は、演算子のオペランドが特定の評価順序 (つまり、左から右) で評価されるように見えることを保証します。

15.7.1 左側のオペランドを最初に評価する

二項演算子の左側のオペランドは、右側のオペランドの一部が評価される前に完全に評価されているように見えます。

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

二項演算子の左側のオペランドの評価が突然終了した場合、右側のオペランドのどの部分も評価されていないように見えます。

セクション 15.26.2 (529 ページ)で詳細に説明されています。

左側のオペランド式が配列アクセス式でない場合、次のようになります。

• 最初に、左側のオペランドが評価されて変数が生成されます。【トリミング】

• それ以外の場合、左側のオペランドの値が保存され、次に右側のオペランドが評価されます。【トリミング】

• それ以外の場合、左側の変数の保存された値と右側のオペランドの値を使用して、複合代入演算子によって示される二項演算が実行されます。【トリミング】

• それ以外の場合、二項演算の結果は左側の変数の型に変換され、適切な標準値セット (拡張指数値セットではない) への値セット変換 (§5.1.13) を受けて、変換結果は変数に格納されます。

ドキュメントの例

例 15.26.2-2。複合代入の左辺の値は右辺の評価前に保存される

  class Test {
      public static void main(String[] args) {
          int k = 1;
          int[] a = { 1 };
          k += (k = 4) * (k + 2);
          a[0] += (a[0] = 4) * (a[0] + 2);
          System.out.println("k==" + k + " and a[0]==" + a[0]);
      }
  }

したがって、質問の式は書き直され、次のようにグループ化されます。

i = i ^ (j = j ^ (i = i ^ j));

左側のオペランドが評価されます。

i = 24 ^ (j = 17 ^ (i = 24 ^ 17));
    **

の値がi期待どおりに「更新」されていないため、が にスワップされると、 の値iが 0 になります。24j

于 2012-07-04T08:40:52.333 に答える
1

一番左iは、変更される前に評価されています。

代わりに次のことができます。

j ^= (i ^= j);
i ^= j;

少しコンパクトではありませんが、機能します。

于 2012-07-04T08:43:04.893 に答える
1

i ^= jswap all を 1 つのステートメントで記述することにより、外側の式に対する内側の式の副作用に依存していますi ^= (...)

Java 仕様 (15.26 代入演算子) から:

代入演算子は 12 個あります。すべてが構文的に右結合です (右から左にグループ化されます)。したがって、a=b=c は a=(b=c) を意味し、c の値を b に割り当て、次に b の値を a に割り当てます。

[...]

AssignmentOperator: = *= /= %= += -= <<= >>= >>>= &= ^= |= のいずれか

コードの可読性を考慮する必要がある場合があります。おそらく、swap() というメソッドにコードを入れるか、temp 変数を使用して実際のスワップを行うのが最善でしょう:

int temp = i;
i = j;
j = temp;
于 2012-07-04T08:10:29.273 に答える
0

次のようにします: i ^= j ^ (j = j ^ i ^ j);

于 2014-06-05T21:44:49.827 に答える