Как работает выражение i = i++? [дубликат]

174
26 января 2019, 00:00

На данный вопрос уже ответили:

  • Почему x = x++ не приводит к увеличению значения x в цикле? 4 ответа

Есть код:

 int i = 1;
 i=i++;
 System.out.println(i);

ВНЕЗАПНО

Output:1

Вопрос: Почему выдаёт единицу? Я считаю, что должна дать двойку. Ну и что что постфиксная запись? Даже если оно сначала бы присвоила i единицу, то потом всё равно должно было увеличить значение i на единицу.

PS. Мне хочется получить ответ по шагам, типа:

  1. Сначала оно делает это, потому что...

  2. Потом оно делает это, потому что...

Answer 1

Возможно понятнее будет на уровне байткода. Ваш код будет скомпилирован в

 0: iconst_1             // Загрузить константу 1 в стек
 1: istore_1             // Сохранить значение из стека в локальную переменную i
 2: iload_1              // Загрузить значение локальной переменной i в стек (в стеке 1)
 3: iinc          1, 1   // Увеличить значение локальной переменной i на 1 (в переменной теперь 2)
 6: istore_1             // СОХРАНИТЬ ЗНАЧЕНИЕ ИЗ СТЕКА В ПЕРЕМЕННУЮ i (в переменной опять 1)
 7: getstatic     #2
10: iload_1              // Загрузить в стек значение переменной i
11: invokevirtual #3     // Вывести значение

Я не нашёл конкретного описания этого поведения в Java Language Specification, но оно не противоречит разделам 15.14.2 и 15.26.1 описывающим порядок разбора выражений постинкремента и присваивания.

Answer 2
int i = 1;
// вместо i = i++;
int __temp = i;
i = i + 1;
i = __temp;
System.out.println(i);

Что происходит в строке

i = i++;

Сначала вычисляется правая часть. Запоминается значение i (равное 1). Потом значение i увеличивается на один. Потом возвращается запомненное значение 1. Потом выполняется присваивание значения 1 переменной i.

Это то же самое, что написано в других ответах.

Answer 3

В вашем примере используется post-increment (i++), в этом случае вы сначала получите старое значение, а уже затем добавите один к текущему значению(++). Чтобы получить 2 необходимо использовать pre-increment: ++i (прошу заметить инкремент перед именем переменной).

Answer 4

Вот смотрите, такой код:

 int i = 1;
    i = i++;
    int a = i;
    System.out.println(a + "" + i);
    int b = i++;
    System.out.println(b + "" + i);

выводит

11 // обратите внимание, что i снова вернулось значение 1
12 // i уже равно 2, но b получает старое значение i

то есть, выражение N=i++ действительно увеличивает i на единицу, но переменной N будет присвоено значение, которое было у i до увеличения - по такому закону работает постфикс.

"Изюминка" в вашем вопросе состоит в том, что переменную i вы действительно увеличили на единицу, но потом "внезапно" той же переменной i присвоили значение, которое было до увеличения - и переменная i у вас снова стала равна 1.

Ответ "по шагам": причина такого результата в следующем - сначала делается операция увеличения i на единицу, а потом делается операция присвоения левой переменной значения i, которое было вначале. Если и слева и справа одна и та же переменная, то вторая операция естественно "затирает" все предыдущие операции.

Answer 5
int i = 1; // i=1
i++        // i=2, значение выражения 1
i = ...;   // присвоить 1 в переменную i - получается i=1
Answer 6

Дружище для начала надо понять как работает оператор ++ есть

int i = 1;
 OperatorPlusPlus(i);
     int OperatorPlusPlus(int yourNumber){
              int tmp = yourNumber;
              int yourNumber = yourNumber + 1;
               return tmp;
    }

То есть вы получаете значение переменной tmp и i у вас равна 2, далее вы i (2) присваивание значение tmp(1)

Answer 7

Начнём с азов работы инкремента.

Возьмём пример:

int x = 1;
int y = x++;
System.out.println(y +""+x);

Output:12

В первом приближении может казаться, что во второй строчке произошло следующее:

  1. Сначала произошло присвоение текущего значения, в переменную y записали единицу.
  2. Потом переменная x увеличилась на единицу.

Однако более пристальный взгляд, говорит что всё оказалось гораздо сложнее. Для этого нужно глянуть декомпилированный байт-код этого же примера:

byte x = 1; //int x = 1 - ориг. код
byte var10000 = x;  //2 строка ориг. кода
int x1 = x + 1;     //2 строка ориг. кода
byte y = var10000; //2 строка ориг. кода
System.out.println(y + "" + x1);

Из него, можно вполне видеть, что эквивалентом "простой" строчки int y = x++;становятся сразу три строки. Похоже они работают следующим образом:

  1. Сначала выделяется переменная var10000 в которую записывается x;
  2. После происходит создание переменной x1 в которой происходит увеличение значения на единицу.
  3. Далее переменной y присваивается значение var10000 - то есть старого значения x.

    Получается, что префиксный инкремент содержит в себе создание двух новых переменных.

Из вышесказанного очевидно, что исходное выражение:

int i = 1;
i=i++;
System.out.println(i);

в декомпилированном байт коде будет выглядеть, как:

 byte i = 1; //x заменили на i
 byte var10000 = i;
 int i1 = i + 1;
 i = var10000; //Мы по сути y заменили i
 System.out.println(i);

То есть, последняя операция перед выводом на консоль - это запись в переменную i временного значения. В соответствии с приоритетом операций, присваивание всегда выполняется после инкремента\декремента.

PS. Дополнительно, на аналогичный вопрос дали 17! ответов в английском стэковерфлоу.

READ ALSO
ScrollingMovementMethod -отключить потемнение при нажатии

ScrollingMovementMethod -отключить потемнение при нажатии

В приложении использую прокрутку в Textview с помощью метода ScrollingMovementMethod()Все отлично работает, но очень раздражает, что при нажатии на Textview...

194
Помогите разобраться в UML диаграмме

Помогите разобраться в UML диаграмме

подскажите по UML диаграмме, с трудом понимаю что данное приложение должно делать, если я верно понял то оно должно анализировать выраженияС-класс...

194
Получить индекс элемента в foreach цикле

Получить индекс элемента в foreach цикле

Есть ли возможность в java получить индекс элемента коллекции в цикле foreach?

206
Книги и учебные ресурсы по Android

Книги и учебные ресурсы по Android

Давайте соберем подборку хорошей литературы и ресурсов (для разработчиков с разным уровнем владения материалом) по ОС Android (архитектура,...

189