English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Обычно считают, что оператор前置 ++ сначала увеличивает значение переменной на 1, а затем использует это значение в вычислении; а оператор постfixed ++ сначала использует это значение в вычислении, а затем увеличивает переменную.
Сначала посмотрим на первый пример:
package test; public class Plus_Test01 { public static void main(String[] args) { int i = 100; i = i++; System.out.println(i); } }
Загадайте результат?
Давайте посмотрим на второй:
package test; public class Plus_Test02 { public static void main(String[] args) { int k = 100; while (true) { if (k++ > 100) { // System.out.println(k); break; } System.out.println(k); } } }
Загадайте результат?
На самом деле, как перед++, так и после++, сначала увеличивают значение переменной, а затем продолжают вычисления. Реальное различие между ними в том, что перед++ увеличивает значение переменной, а затем использует увеличенное значение для вычислений, а после++ сначала присваивает значение переменной временной переменной, затем увеличивает значение переменной и использует эту временную переменную для вычислений.
Для是这样的 код фрагмента (перед++):
int i=1;
int j=++i*5;
На самом деле, вторая строка эквивалентна:
i+=1; //i увеличивается на 1
j=i*5; //Вычисление с увеличенным значением, результат: 10
А для是这样的代码 фрагмента (после++):
int i=1;
int j=i++*5;
Вторая строка эквивалентна:
int temp=i; //Адресуется к временной переменной
i+=1; //i увеличивается на 1
j=temp*5; //Вычисление с временной переменной, результат: 5
Для первого примера это эквивалентно:
int temp=i;
i+=1;
i=temp; //
Таким образом, результат должен быть неизменным, то есть 100.
Асsembly кода первого примера:
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Код: stack=2, locals=2, args_size=1 0: bipush 100 2: istore_1 3: iload_1 4: iinc 1, 1 //Локальная переменная второго увеличивается на 1 7: istore_1 //Сохраняется в локальной переменной 8: getstatic #16 // Поля java/lang/System.out:Ljava/io/PrintStream; 11: iload_1 //Загружаемый параметр из стека - второй, то есть все еще 100 12: invokevirtual #22 // Метод java/io/PrintStream.println:(I)V 15: return
Для второго примера это не сложно, результат 101, обратите внимание на процесс, в будущем не следует犯这样的错误. (Процесс: сначала сравнивается temp=i, temp>100,显然不成立,и+=1, переходит к строке syso, выводится конечно 101, снова цикл temp=i, temp>100, теперь это уже установлено, и+=1, directamente выходит из цикла, не выполняет инструкции в while).
Асsembly примера второго (выбран только метод main):
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Код: stack=2, locals=2, args_size=1 0: bipush 100 //100 на стек 2: istore_1 //сохранение в второго локального переменного (первый локальный переменный - это аргумент метода) 3: iload_1 //загрузка второго локального переменного 4: iinc 1, 1 //увеличение значения int в локальной переменной 2 (локальная переменная инкрементируется, результат все еще в локальной переменной, вершине стека 1 не изменяется) 7: bipush 100 //100 на стек 9: if_icmple 15 //сравнение двух int целых чисел в вершине стека, если первое меньше или равно второму, то перепрыгивание на 15 строку 12: goto 25 //иначе перепрыгивание на 25 строку (т.е. операнд в вершине стека 1>операнд в вершине стека 2) 15: getstatic #2 // Поле java/lang/System.out:Ljava/io/PrintStream; 18: iload_1 // //загрузка первого локального переменного 19: invokevirtual #3 // Метод java/io/PrintStream.println:(I)V //вызов этого метода 22: goto 3 //повторное перепрыгивание на 3, повторный цикл 25: return //выход
Третий пример:
package test; public class Plus_Test03 { static int proPlus() { int i = 55; int j = ++i; return j; //56 } static int postPlus() { int i = 55; int j = i++; return j; //55 } public static void main(String[] args) { System.out.println(proPlus());//56 System.out.println(postPlus());//55 } }
Третий пример:
static int proPlus(); descriptor: ()I flags: ACC_STATIC Код: стэк=1, locals=2, args_size=0 0: bipush 55 //55 загрузить в стэк 2: istore_0 //сохранить int из стэка в первый local var 3: iinc 0, 1 //первый local var увеличен на 1 6: iload_0 //загрузить из local var 7: istore_1 //сохранить во второй local var 8: iload_1 //стэк頂ка - второй local var 9: ireturn static int postPlus(); descriptor: ()I flags: ACC_STATIC Код: стэк=1, locals=2, args_size=0 0: bipush 55 2: istore_0 3: iload_0 //загрузить в стэк 4: iinc 0, 1 //первый local var увеличен на 1 7: istore_1 8: iload_1 9: ireturn
Таким образом, различия между предфикс и постфикс ++ заключаются в части, указанной на синем фоне (//первый local var увеличен на 1), эти две части обратны. Для предфикса, он увеличит значение local var и затем загрузит его в стэк, а для постфикса сначала загрузит local var в стэк, а затем увеличит local var, что эквивалентно созданию резервной копии.
Заключение:
Первый. Предфикс и постфикс ++ оба сначала увеличивают значение переменной на 1, но не то, что предфикс ++ сначала увеличивает, а затем выполняет вычисление, а постфикс ++ сначала выполняет вычисление, а затем увеличивает.
Второй. С точки зрения программы, постфикс ++ сначалаassign переменную в временный переменную, затем увеличивает значение переменной на 1, и затем использует этот временный переменную в вычислениях.
Третий. С точки зрения инструкций, постфикс ++ сначала сохраняет значение переменной на стэк, а затем выполняет инструкцию增值 (iinc), после чего использует значение, сохраненное на стэк.
Надеюсь, что с помощью этой статьи вы сможете полностью понять различия между предшествующим и последующим ++ операторами, спасибо всем за поддержку нашего сайта!