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), после чего использует значение, сохраненное на стэк.

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

Вам может понравиться