14
int x=1;
int y=2;
x ^= y ^= x ^= y;

値が入れ替わると思いますが、x=0とy=1になります。C言語で試してみると、正しい結果が得られます。

4

2 に答える 2

57

あなたのステートメントは、次の展開された形式とほぼ同じです。

x = x ^ (y = y ^ (x = x ^ y));

C とは異なり、Java では、二項演算子の左オペランドが右オペランドより先に評価されることが保証されています。評価は次のように行われます。

x = x ^ (y = y ^ (x = x ^ y))
x = 1 ^ (y = 2 ^ (x = 1 ^ 2))
x = 1 ^ (y = 2 ^ (x = 3))
x = 1 ^ (y = 2 ^ 3)             // x is set to 3 
x = 1 ^ (y = 1)
x = 1 ^ 1                       // y is set to 1
x = 0                           // x is set to 0

各 xor 式の引数の順序を逆にして、変数が再度評価される前に割り当てが行われるようにすることができます。

x = (y = (x = x ^ y) ^ y) ^ x
x = (y = (x = 1 ^ 2) ^ y) ^ x
x = (y = (x = 3) ^ y) ^ x 
x = (y = 3 ^ y) ^ x             // x is set to 3
x = (y = 3 ^ 2) ^ x
x = (y = 1) ^ x
x = 1 ^ x                       // y is set to 1
x = 1 ^ 3
x = 2                           // x is set to 2

これは、よりコンパクトなバージョンでも機能します。

x = (y ^= x ^= y) ^ x;

しかし、これは 2 つの変数を入れ替える本当に恐ろしい方法です。一時変数を使用することをお勧めします。

于 2010-10-02T08:29:53.270 に答える
15

マークは、Java での評価方法について完全に正しいです。その理由は JLS §15.7.2 です。、操作の前にオペランドを 評価し、左から右への評価が必要な§15.7 :

これは ( §15.26.2複合代入演算子による) 以下と同等です。

x = x ^ (y = y ^ (x = (x ^ y)));

演算の前に両方のオペランドを実行して、左から右に評価します。

x = 1 ^ (y = y ^ (x = (x ^ y))); // left of outer 
x = 1 ^ (y = 2 ^ (x = (x ^ y))); // left of middle 
x = 1 ^ (y = 2 ^ (x = (1 ^ y))); // left of inner
x = 1 ^ (y = 2 ^ (x = (1 ^ 2))); // right of inner
x = 1 ^ (y = 2 ^ (x = 3)); // inner xor (right inner assign)
x = 1 ^ (y = 2 ^ 3); // inner assign (right middle xor)
x = 1 ^ (y = 1); // middle xor (right middle assign)
x = 1 ^ 1; // middle assign (right outer xor)
x = 0; // outer xor (right outer assign)

シーケンス ポイント間で同じ変数を 2 回変更しているため、C では未定義の動作であることに注意してください。

于 2010-10-02T08:32:54.873 に答える