В коде я много раз вижу x++циклы, но иногда обнаруживаю у себя ++x.
Если вы имеете в виду конструкции такого типа:
public static void main(String[] args) {
for (int i = 0; i < 10; ++i) {
System.out.println(i);
}
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
... тогда нет никакой разницы. Если мы видим байт -код :
В обоих случаях сразу после вызова println( invokevirtual #3) переменная 1 (в коде она есть для обоих случаев) увеличивается iна 1. См. iinc 1, 1перед goto.
Однако, если вы имеете в виду что-то вроде этого:
public static void main(String[] args) {
for (int i = 0; i < 10;) {
System.out.println(i++);
}
for (int i = 0; i < 10;) {
System.out.println(++i);
}
}
В первом случае значение переменной 1 ( i) загружается первым для использования в println. См iload_1. . Затем эта переменная увеличивается на 1. См iinc 1, 1. .
Во втором случае значение переменной 1 ( i) сначала увеличивается на 1, см iinc 1, 1. . Затем загружается значение переменной 1( i) для использования в файле println. См iload_1. .
...Значением постфиксного выражения приращения является значение переменной перед сохранением нового значения.
Перевод
15.14.2. Постфиксный оператор приращения ++
Значением постфиксного выражения приращения является значение переменной перед сохранением нового значения.
В равной степени
15.15.1. Префиксный оператор приращения ++
Значение выражения приращения префикса — это значение переменной после сохранения нового значения.
Перевод
15.15.1. Префиксный оператор приращения ++
Значение выражения приращения префикса — это значение переменной после сохранения нового значения.
Оба увеличивают переменную xна 1. Разница в том, что выражение ++xвозвращает значение увеличенной переменной, а выражение x++возвращает исходное значение переменной до увеличения.
А именно:
int x = 5;
System.out.println(++x); // Imprime 6, x vale 6: El resultado de la expresión ++x es 6 y se imprime 6
System.out.println(x); // Imprime 6, x vale 6: x ya se incrementó por lo que devuelve 6
Пока:
int x = 5;
System.out.println(x++); // Imprime 5, x vale 6. La variable x ya es 6 pero el resultado de la expresión es 5 por lo que se imprime 5
System.out.println(x); // Imprime 6, x vale 6: x ya se incrementó por lo que devuelve 6
Я знаю, что вопрос помечен на Java, и я не знаю реализации на этом языке (хотя я предполагаю, что она будет похожей), но на C#, хотя это нормально и интуитивно понятно, что «один возвращает значение до приращение, а другое после" , и это более или менее дает основной смысл... реальность такова, что реализация не такая, и у нее очень специфическая последовательность событий.
Это не проблема, если мы используем его отдельно: x++;это не приносит никаких проблем, и простое объяснение действительно... но если мы попадаем в многопоточность и длинные операции с разными приоритетами операторов, все меняется.
Как я уже сказал, я не знаю, как это делает Java, но в C# последовательность каждой команды четко определена (и я думаю, что в Java она будет аналогичной):
Для типа префикса ( ++x) последовательность следующая:
Оценивается x, чтобы произвести переменную
Значение переменной копируется во временное пространство
Временная переменная увеличивается и создает новое значение (которое не перезаписывает временное)
Новое значение сохраняется в переменной
Возвращается новое значение ( не переменная )
Для типа суффикса ( x++) последовательность следующая:
Оценивается x, чтобы произвести переменную
Значение переменной копируется во временное пространство
Временная переменная увеличивается и создает новое значение (которое не перезаписывает временное)
Новое значение сохраняется в переменной
Возвращается значение временной копии
Поэтому последовательность событий происходит в обоих случаях в одном и том же порядке, и ни оценка, ни приращение переменной не меняются, меняется только возвращаемое значение. Разница только в шаге 5.
В С#, используя расширения методов, это очень легко проверить... в Java я не так ясен (у меня есть только базовые понятия о Java).
Извините, что отвечаю с использованием C #, с вопросом, помеченным как Java, но, как я уже сказал, я подозреваю, что реализация должна быть похожей, если не такой же.
Оба увеличивают значение переменной на 1. Если вы используете их в строке, где это единственное выражение, нет никакой разницы, но если вы выполняете их вместе с другими, есть важная вариация.
++x делает это перед вычислением выражения. Это также называетсяPREINCREMENTO
Пример:
int x = 5;
System.out.println(++x); // escribira 6 porque ejecutará x + 1 ANTES de printar
System.out.println(x); // volverá a escribir 6!!!!
x++ делает это после вычисления выражения. Это также называетсяPOSTINCREMENTO
Пример:
int x = 5;
System.out.println(x++); // escribirá 5 porque ejecutará x + 1 DESPUÉS de printar
System.out.println(x); // escribirá 6
Этот тип выражения также очень распространен при выполнении присваиваний из массива, когда вы выполняете цикл без счетчика (например, for-each) или заполняя различные свойства одного и того же объекта, таким образом экономя строку кода и получая читабельность.
Они оба делают одно и то же, за исключением того, что постинкремент оценивается как значение переменной ДО того, как увеличенное значение будет сохранено, а предварительный инкремент оценивается как значение переменной ПОСЛЕ того, как увеличенное значение будет сохранено.
Приращение до и после определено в Спецификации языка Java (JLS) в двух разделах, из которых я воспроизвожу переведенные части, важные для этого вопроса (выделено мной):
15.14.2: Оператор приращения постфикса ++
(..опущено..)
Во время выполнения, если вычисление выражения завершается внезапно, то выражение приращения постфикса завершается внезапно по той же причине, и приращение отсутствует. В противном случае значение 1 добавляется к значению переменной, и сумма сохраняется в переменной. (...опущено...) Значением постфиксного выражения приращения является значение переменной перед сохранением нового значения.
(..опущено..)
15.15.1. Оператор приращения префикса ++
(..опущено..)
Если во время выполнения вычисление выражения завершается внезапно, то выражение декремента префикса завершается внезапно по той же причине, и приращение не происходит. В противном случае значение 1 добавляется к значению переменной, и сумма сохраняется в переменной. (...опущено...) Значением постфиксного выражения приращения является значение переменной после сохранения нового значения.
(..опущено..)
Обратите внимание, что все то же самое, за исключением значения, с которым оценивается выражение, которое является значением, которое переменная имела до того, как новое значение, увеличенное для постфиксного приращения, было сохранено, и является значением, которое имеет переменная после того, как она была увеличена для приращение префикса.
Все это не имеет значения в коде, подобном следующему:
for ( int n=1; n<10; ++n)
for ( int n=1; n<10; n++)
В этом коде для одного и того же значения nвыражения ++nи n++оцениваются в разные значения, но это не имеет значения, так как это значение не используется, и единственное, что оказывает существенное влияние, это то, что переменная увеличивается на 1, что Это происходит в обоих случаях. Оба цикла будут выполнять одинаковое количество итераций.
Но это важно в коде, подобном следующему:
int a; int b;
a = 3;
b = a++;
System.out.println( "a="+a + " b=" + b);
a = 3;
b = ++a;
System.out.println( "a="+a + " b=" + b);
Где вывод:
а=4 б=3
а=4 б=4
В выражении вычисляется b = a++переменная a(которая равна 3), к этому значению прибавляется 1 и результат суммы (4) сохраняется в переменной a. Результатом выражения a++является значение, которое переменная имеет aдо того, как новое значение (которое было 3) будет сохранено в ней, поэтому результат выражения a++равен 3. И это, 3, хранится в b.
В выражении вычисляется b = ++aпеременная a(которая равна 3), к этому значению прибавляется 1 и результат суммы (4) сохраняется в переменной a. Результатом выражения ++aявляется значение, которое имеет переменная aпосле сохранения в ней нового значения (которое равно 4), поэтому результат выражения ++aравен 4. И это, 4, хранится в b.
Строго следуя этому способу вычисления приращения префикса и постфикса, мы можем правильно вычислить любое выражение, в котором они участвуют. Например :
int a; int b;
a = 3;
b = ++a + a++;
System.out.println( "a="+a + " b=" + b);
a = 3;
b = a++ + a++;
System.out.println( "a="+a + " b=" + b);
В первом выражении bона оказывается равной 8, потому что первая ++aоценивается как 4 (значение после сохранения приращения), а к моменту выполнения второго a++переменная aуже содержит 4, она увеличивается до 5, но значение выражение a++является выражением переменной до увеличения, таким образом оценивая значение 4. И 4+4=8.
Во втором выражении bоно оказывается равным 7, потому что первое a++оценивается как 3 (значение перед сохранением приращения), и к тому времени, когда второе выражение выполняется, a++переменная aуже содержит 4, она увеличивается до 5, но значение выражение a++- это выражение переменной до увеличения, поэтому оно оценивается как 4. И 3 + 4 = 7.
НО ЛУЧШЕ ЭТОГО НЕ ДЕЛАТЬ
Хотя мы полностью понимаем, как работают операторы пре- и постинкремента, их использование в нетривиальных выражениях только запутает. Вам, вашим кооператорам, вашему координатору, тому, кто рецензирует код, тому, кому приходится иметь дело с кодом спустя 5 лет, когда тот, кто его написал, уже давно ушел из компании, коту.. .
ПОСЛЕДНИЙ ИНКРЕМЕНТ :
Пример:
ПРЕДВАРИТЕЛЬНОЕ УВЕЛИЧЕНИЕ :
Пример:
Аналогично для
x--
и--x
Примеры:
Дополнительная информация:
Если вы имеете в виду конструкции такого типа:
... тогда нет никакой разницы. Если мы видим байт -код :
В обоих случаях сразу после вызова
println
(invokevirtual #3
) переменная 1 (в коде она есть для обоих случаев) увеличиваетсяi
на 1. См.iinc 1, 1
передgoto
.Однако, если вы имеете в виду что-то вроде этого:
... тогда есть разница. Проверяем байт -код :
В первом случае значение переменной 1 (
i
) загружается первым для использования вprintln
. Смiload_1
. . Затем эта переменная увеличивается на 1. Смiinc 1, 1
. .Во втором случае значение переменной 1 (
i
) сначала увеличивается на 1, смiinc 1, 1
. . Затем загружается значение переменной 1(i
) для использования в файлеprintln
. Смiload_1
. .Разница не в том, выполняется ли приращение до или после вычисления выражения, а в возвращаемом значении двух выражений.
Согласно официальной спецификации Java в разделе: 15.14.2. Постфиксный оператор приращения++ и 15.15.1. Префиксный оператор приращения ++
Перевод
В равной степени
Перевод
Оба увеличивают переменную
x
на 1. Разница в том, что выражение++x
возвращает значение увеличенной переменной, а выражениеx++
возвращает исходное значение переменной до увеличения.А именно:
Пока:
Я знаю, что вопрос помечен на Java, и я не знаю реализации на этом языке (хотя я предполагаю, что она будет похожей), но на C#, хотя это нормально и интуитивно понятно, что «один возвращает значение до приращение, а другое после" , и это более или менее дает основной смысл... реальность такова, что реализация не такая, и у нее очень специфическая последовательность событий.
Это не проблема, если мы используем его отдельно:
x++;
это не приносит никаких проблем, и простое объяснение действительно... но если мы попадаем в многопоточность и длинные операции с разными приоритетами операторов, все меняется.Как я уже сказал, я не знаю, как это делает Java, но в C# последовательность каждой команды четко определена (и я думаю, что в Java она будет аналогичной):
Для типа префикса (
++x
) последовательность следующая:x
, чтобы произвести переменнуюДля типа суффикса (
x++
) последовательность следующая:x
, чтобы произвести переменнуюПоэтому последовательность событий происходит в обоих случаях в одном и том же порядке, и ни оценка, ни приращение переменной не меняются, меняется только возвращаемое значение. Разница только в шаге 5.
В С#, используя расширения методов, это очень легко проверить... в Java я не так ясен (у меня есть только базовые понятия о Java).
Извините, что отвечаю с использованием C #, с вопросом, помеченным как Java, но, как я уже сказал, я подозреваю, что реализация должна быть похожей, если не такой же.
Оба увеличивают значение переменной на
1
. Если вы используете их в строке, где это единственное выражение, нет никакой разницы, но если вы выполняете их вместе с другими, есть важная вариация.++x делает это перед вычислением выражения. Это также называется
PREINCREMENTO
Пример:
x++ делает это после вычисления выражения. Это также называется
POSTINCREMENTO
Пример:
Этот тип выражения также очень распространен при выполнении присваиваний из массива, когда вы выполняете цикл без счетчика (например, for-each) или заполняя различные свойства одного и того же объекта, таким образом экономя строку кода и получая читабельность.
вместо
++x
увеличивает переменную перед ее вызовом.X++
вызывает его, а затем увеличивает его.Они оба делают одно и то же, за исключением того, что постинкремент оценивается как значение переменной ДО того, как увеличенное значение будет сохранено, а предварительный инкремент оценивается как значение переменной ПОСЛЕ того, как увеличенное значение будет сохранено.
Приращение до и после определено в Спецификации языка Java (JLS) в двух разделах, из которых я воспроизвожу переведенные части, важные для этого вопроса (выделено мной):
15.14.2: Оператор приращения постфикса ++
(..опущено..)
Во время выполнения, если вычисление выражения завершается внезапно, то выражение приращения постфикса завершается внезапно по той же причине, и приращение отсутствует. В противном случае значение 1 добавляется к значению переменной, и сумма сохраняется в переменной. (...опущено...) Значением постфиксного выражения приращения является значение переменной перед сохранением нового значения.
(..опущено..)
15.15.1. Оператор приращения префикса ++
(..опущено..)
Если во время выполнения вычисление выражения завершается внезапно, то выражение декремента префикса завершается внезапно по той же причине, и приращение не происходит. В противном случае значение 1 добавляется к значению переменной, и сумма сохраняется в переменной. (...опущено...) Значением постфиксного выражения приращения является значение переменной после сохранения нового значения.
(..опущено..)
Обратите внимание, что все то же самое, за исключением значения, с которым оценивается выражение, которое является значением, которое переменная имела до того, как новое значение, увеличенное для постфиксного приращения, было сохранено, и является значением, которое имеет переменная после того, как она была увеличена для приращение префикса.
Все это не имеет значения в коде, подобном следующему:
В этом коде для одного и того же значения
n
выражения++n
иn++
оцениваются в разные значения, но это не имеет значения, так как это значение не используется, и единственное, что оказывает существенное влияние, это то, что переменная увеличивается на 1, что Это происходит в обоих случаях. Оба цикла будут выполнять одинаковое количество итераций.Но это важно в коде, подобном следующему:
Где вывод:
В выражении вычисляется
b = a++
переменнаяa
(которая равна 3), к этому значению прибавляется 1 и результат суммы (4) сохраняется в переменной a. Результатом выраженияa++
является значение, которое переменная имеетa
до того, как новое значение (которое было 3) будет сохранено в ней, поэтому результат выраженияa++
равен 3. И это, 3, хранится вb
.В выражении вычисляется
b = ++a
переменнаяa
(которая равна 3), к этому значению прибавляется 1 и результат суммы (4) сохраняется в переменнойa
. Результатом выражения++a
является значение, которое имеет переменнаяa
после сохранения в ней нового значения (которое равно 4), поэтому результат выражения++a
равен 4. И это, 4, хранится вb
.Строго следуя этому способу вычисления приращения префикса и постфикса, мы можем правильно вычислить любое выражение, в котором они участвуют. Например :
В первом выражении
b
она оказывается равной 8, потому что первая++a
оценивается как 4 (значение после сохранения приращения), а к моменту выполнения второгоa++
переменнаяa
уже содержит 4, она увеличивается до 5, но значение выражениеa++
является выражением переменной до увеличения, таким образом оценивая значение 4. И 4+4=8.Во втором выражении
b
оно оказывается равным 7, потому что первоеa++
оценивается как 3 (значение перед сохранением приращения), и к тому времени, когда второе выражение выполняется,a++
переменнаяa
уже содержит 4, она увеличивается до 5, но значение выражениеa++
- это выражение переменной до увеличения, поэтому оно оценивается как 4. И 3 + 4 = 7.НО ЛУЧШЕ ЭТОГО НЕ ДЕЛАТЬ
Хотя мы полностью понимаем, как работают операторы пре- и постинкремента, их использование в нетривиальных выражениях только запутает. Вам, вашим кооператорам, вашему координатору, тому, кто рецензирует код, тому, кому приходится иметь дело с кодом спустя 5 лет, когда тот, кто его написал, уже давно ушел из компании, коту.. .