Что такое х после "х = х ++"? - PullRequest
       66

Что такое х после "х = х ++"?

268 голосов
/ 27 октября 2011

Что происходит (за занавесом), когда это выполняется?

int x = 7;
x = x++;

То есть, когда переменная увеличивается на единицу и присваивается себе в одном выражении? Я скомпилировал и выполнил это. x по-прежнему 7 даже после всего утверждения . В моей книге говорится, что x увеличивается!

Ответы [ 17 ]

372 голосов
/ 27 октября 2011
x = x++;

эквивалентно

int tmp = x;
x++;
x = tmp;
284 голосов
/ 27 октября 2011

x увеличивается.Но вы присваиваете себе старое значение x.


x = x++;
  1. x++ увеличивает x и возвращает старое значение.
  2. x = присваивает старое значение обратно себе.

Таким образом, в итоге x возвращается обратно к своему начальному значению.

256 голосов
/ 20 августа 2012

утверждение:

x = x++;

эквивалентно:

tmp = x;   // ... this is capturing the value of "x++"
x = x + 1; // ... this is the effect of the increment operation in "x++" which
           //     happens after the value is captured.
x = tmp;   // ... this is the effect of assignment operation which is
           //     (unfortunately) clobbering the incremented value.

Короче говоря, заявление не имеет никакого эффекта.

Ключевые моменты:

  • Значением выражения приращения / уменьшения Postfix является значение операнда до , при котором происходит увеличение / уменьшение. (В случае формы префикса значением является значение операнда после операции,)

  • RHS выражения присваивания полностью оценивается (включая любые приращения, уменьшение и / или другие побочные эффекты) до значение присваивается LHS.

Обратите внимание, что в отличие от C и C ++, порядок вычисления выражения в Java полностью определен, и нет места для изменения, зависящего от платформы. Компиляторам разрешено переупорядочивать операции только в том случае, если это не изменит результат выполнения кода с точки зрения текущего потока. В этом случае компилятору будет разрешено оптимизировать весь оператор, поскольку можно доказать, что он не используется.


В случае, если это еще не очевидно:

  • "х = х ++;" почти наверняка ошибка в любой программе.
  • OP (для исходного вопроса!), Вероятно, означало "x ++;" вместо "x = x ++;".
  • Сложно понять операторы, сочетающие автоматическое увеличение / уменьшение и присвоение для одной и той же переменной, и поэтому следует избегать независимо от их правильности . Просто нет необходимости писать такой код.

Надеемся, что программы проверки кода, такие как FindBugs и PMD, будут отмечать код как подозрительный.

33 голосов
/ 27 октября 2011
int x = 7;
x = x++;

Он имеет неопределенное поведение в C и для Java см. этот ответ . Что зависит от компилятора, что произойдет.

16 голосов
/ 20 августа 2012

Конструкция типа x = x++; указывает, что вы, вероятно, неправильно понимаете, что делает оператор ++:

// original code
int x = 7;
x = x++;

Давайте перепишем это, чтобы сделать то же самое, основываясь на удалении оператора ++:

// behaves the same as the original code
int x = 7;
int tmp = x; // value of tmp here is 7
x = x + 1; // x temporarily equals 8 (this is the evaluation of ++)
x = tmp; // oops! we overwrote y with 7

Теперь, давайте перепишем его, чтобы сделать (что я думаю), что вы хотели:

// original code
int x = 7;
x++;

Тонкость здесь заключается в том, что оператор ++ изменяет переменную x, в отличие от такого выражения, как x + x, которое будет вычислять значение int, но сама переменная x не изменится.Рассмотрим такую ​​конструкцию, как почтенный цикл for:

for(int i = 0; i < 10; i++)
{
    System.out.println(i);
}

Обратите внимание на i++ там?Это тот же оператор.Мы могли бы переписать этот цикл for следующим образом:

for(int i = 0; i < 10; i = i + 1)
{
    System.out.println(i);
}

Я также рекомендую не использовать оператор ++ в больших выражениях в большинстве случаев.Из-за тонкости , когда изменяет исходную переменную до пост-приращения (++x и x++ соответственно), очень легко вводить тонкие ошибки, которые трудно отследить.

13 голосов
/ 28 августа 2014

Согласно байт-коду , полученному из файлов классов,

Оба приращения увеличиваются по x, но разница - это время when the value is pushed onto the stack

В Case1, Push происходит (и затем назначается позже) до приращения (по сути, это означает, что ваш прирост ничего не делает)

В Case2 сначала происходит инкремент (равен 8), а затем помещается в стек (а затем присваивается x)

Дело 1:

int x=7;
x=x++;

Байт-код:

0  bipush 7     //Push 7 onto  stack
2  istore_1 [x] //Pop  7 and store in x
3  iload_1  [x] //Push 7 onto stack
4  iinc 1 1 [x] //Increment x by 1 (x=8)
7  istore_1 [x] //Pop 7 and store in x
8  return       //x now has 7

Дело 2:

int x=7; 
x=++x;

Байт-код

0  bipush 7     //Push 7 onto stack
2  istore_1 [x] //Pop 7 and store in x
3  iinc 1 1 [x] //Increment x by 1 (x=8)
6  iload_1  [x] //Push x onto stack
7  istore_1 [x] //Pop 8 and store in x
8  return       //x now has 8
  • Стек здесь относится к стеку операндов, локальный: x index: 1 тип: int
9 голосов
/ 27 октября 2011

Увеличивается после "x = x++;". Было бы 8, если бы вы сделали "x = ++x;".

7 голосов
/ 25 февраля 2014

Оператор пост-инкремента работает следующим образом:

  1. Сохранить предыдущее значение операнда.
  2. Увеличить значение операнда.
  3. Возвращает предыдущее значение операнда.

Итак, утверждение

int x = 7;
x = x++; 

будет оцениваться следующим образом:

  1. x инициализируется значением 7
  2. Оператор постинкрементного хранения сохраняет предыдущее значение x, т. Е. 7 для возврата.
  3. Увеличивает x, , поэтому теперь x равно 8
  4. Возвращает предыдущее значение x, то есть 7, и оно присваивается обратно x, поэтому x снова становится 7

Таким образом, x действительно увеличивается, но поскольку x ++ присваивает результат обратно x, то значение x переопределяется на его предыдущее значение.

7 голосов
/ 27 октября 2011

При повторном присвоении значения для x оно все равно 7. Попробуйте x = ++x, и вы получите 8, а затем выполните

x++; // don't re-assign, just increment
System.out.println(x); // prints 8
7 голосов
/ 27 октября 2011

Инкремент происходит после вызова x, поэтому x по-прежнему равен 7. ++ x будет равен 8 при вызове x

...