Почему это утверждение не работает в Java x ^ = y ^ = x ^ = y; - PullRequest
14 голосов
/ 02 октября 2010
int x=1;
int y=2;
x ^= y ^= x ^= y;

Я ожидаю, что значения будут поменяны местами. Но это дает x = 0 и y = 1.когда я попробовал на языке C, это дает правильный результат.

Ответы [ 2 ]

57 голосов
/ 02 октября 2010

Ваше утверждение примерно эквивалентно этой расширенной форме:

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;

Но это действительно ужасный способ поменять две переменные.Намного лучше использовать временную переменную.

14 голосов
/ 02 октября 2010

Марк полностью прав насчет того, как он оценивает в 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)

Обратите внимание, что этонеопределенное поведение в C, потому что вы изменяете одну и ту же переменную дважды между точками последовательности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...