Разница в реализации x = x + 1 и x ++

Мой профессор недавно сказал, что, хотя x = x + 1 и x++, очевидно, дадут одинаковый результат, есть разница в том, как они реализованы в JVM. Что это значит? Разве компилятор не такой: эй, я вижу x++, поэтому я переключу его на x = x + 1 и продолжу?

Я сомневаюсь, что есть какая-то разница в эффективности, но я был бы удивлен, если бы сборка в этих случаях была бы другой ...


person Eleeist    schedule 22.10.2013    source источник
comment
Это будет дубликат.   -  person Alec Teal    schedule 23.10.2013
comment
Для ясности, должна быть разница между ++ x и x ++, но не между x ++ и x = x + 1 или даже x + = 1, когда используется как отдельное выражение.   -  person drobert    schedule 23.10.2013
comment
Это не должно быть отвергнуто - это прекрасный вопрос. И @AlecTeal вы должны предоставить дубликат, если он существует.   -  person sdasdadas    schedule 23.10.2013
comment
Операторы увеличения и уменьшения могут быть размещены до (префикс) или после (постфикс) переменной, к которой они применяются. Если вы поместите оператор увеличения или уменьшения перед его переменной, оператор применяется до того, как будет оценена остальная часть выражения. Если вы поместите оператор после переменной, он применяется после вычисления выражения.   -  person user20232359723568423357842364    schedule 23.10.2013
comment
@drobert Действительно есть разница между x ++ и x = x + 1. Посмотрите, это дубликат на ТАК много раз ...   -  person buzzsawddog    schedule 23.10.2013
comment
Мне нравится, как много людей утверждают, что это дубликат, не публикуя ссылку.   -  person Cruncher    schedule 23.10.2013
comment
Для моей личной выгоды здесь кажется, что после int x = 0; все следующие автономные выражения дают идентичный байт-код: x + = 1 / x ++ / ++ x Имеет смысл после чтения 'iinc'. Всем спасибо за ссылки.   -  person drobert    schedule 23.10.2013
comment
@buzzsawddog не говорит ни о ++ ни в вопросе, ни в ответе.   -  person Cruncher    schedule 23.10.2013
comment
Упс, неправильная ссылка ... Я посмотрю, смогу ли я найти ссылку только для вас @Cruncher, потому что похоже, что ваш гугл не работает ...   -  person buzzsawddog    schedule 23.10.2013


Ответы (2)


Мой профессор недавно сказал, что, хотя x = x + 1 и x ++, очевидно, дадут один и тот же результат

Думаю, ваш профессор, возможно, имел в виду - значение x после x = x + 1 и x++ будет одинаковым. Просто перефразирую, поскольку это, кажется, создает путаницу при интерпретации вопроса.

Что ж, хотя значение x будет одинаковым, это разные операторы и используют разные инструкции JVM в байт-коде. x + 1 использует iadd. инструкция, тогда как x++ использует iinc < / a> инструкция. Хотя это зависит от компилятора. Компилятор может использовать другой набор инструкций для конкретной операции. Я проверил это по javac компилятору.

Для компилятора eclipse из одного из комментариев ниже от @Holger:

Я только что протестировал его с помощью eclipse, и он дал iinc для обоих выражений. Итак, я нашел один компилятор, производящий такие же инструкции

Вы можете проверить байтовый код с помощью команды javap. Рассмотрим следующий класс:

class Demo {
    public static void main(String[] args) {
        int x = 5;

        x = x + 1;
        System.out.println(x);

        x++;
        System.out.println(x);
    }
} 

Скомпилируйте указанный выше исходный файл и выполните следующую команду:

javap -c Demo

Код будет скомпилирован в следующий байт-код (просто показан метод main):

 public static void main(java.lang.String[]);
   Code:
      0: iconst_5
      1: istore_1
      2: iload_1
      3: iconst_1
      4: iadd
      5: istore_1
      6: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      9: iload_1
     10: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
     13: iinc          1, 1
     16: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
     19: iload_1
     20: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
     23: return
person Rohit Jain    schedule 22.10.2013
comment
+1 за фактический ответ на вопрос вместо того, чтобы говорить о чем-то совершенно другом, что также связано с операторами инкремента ;-) - person ; 23.10.2013
comment
@Bohemian x += 1 фактически использует только инструкцию iinc. 2-й параметр будет 2 для x += 2. - person Rohit Jain; 23.10.2013
comment
Они разные! Следовательно, байт-код не может быть таким же, кроме как в некоторых оптимизированных случаях. - person Ingo; 23.10.2013
comment
Естественно, как только у них закончатся инструкции байт-кода, им придется устранить одну из них. Как Oracle обрабатывает java, они, вероятно, исключат iadd и заменят все существующие iadds на циклы iinc. - person corsiKa; 23.10.2013
comment
Мне нравится, как это не заметил оптимизатор глазка. - person Alec Teal; 23.10.2013
comment
@corsiKa Я сомневаюсь, что это произойдет. - person Rohit Jain; 23.10.2013
comment
@corsiKa нет абсолютно никакого способа, чтобы они уронили iadd и зациклили iinc. Это совершенно глупо. Конечно, они отбросили бы iinc и просто использовали iadd для увеличения ... Я бы предпочел, чтобы они увеличили размер инструкций, увеличивая размер всех файлов .class, прежде чем зацикливать iincs ... - person Cruncher; 23.10.2013
comment
@delnan - могут быть разные компиляторы. Не написано на камне, что компилятор не мог использовать iinc для x = x + 1 при определенных обстоятельствах. - person Ingo; 23.10.2013
comment
@Ingo Я думаю, что касается компиляции кода Java в байт-код, он должен следовать набору инструкций JVM. Компилятор не может волшебным образом заставить JVM использовать iinc вместо x = x + 1. - person Rohit Jain; 23.10.2013
comment
@Ingo И как это оправдывает то, что вы проголосовали против этого ответа? Вы можете объяснить, какая часть не отвечает на вопрос? - person Rohit Jain; 23.10.2013
comment
@RohitJain Вы говорите, что iload x; iinc; dup; istore x недействителен для x = x + 1? - person Ingo; 23.10.2013
comment
@Ingo Я этого не говорил? - person Rohit Jain; 23.10.2013
comment
@Ingo Ну, я догадался, потому что это произошло одновременно с твоим комментарием. Не обращайте внимания на комментарий, если вы этого не сделали :) - person Rohit Jain; 23.10.2013
comment
@RohitJain В указанном вами байт-коде инструкции 3 и 4 можно заменить на iinc. Ничто не мешает другому компилятору сделать это. (Не то чтобы это имело значение). - person Ingo; 23.10.2013
comment
@Cruncher Я ... я не ... я даже не знаю, как ответить, если вы хоть как-то серьезно отнеслись к моему комментарию. - person corsiKa; 23.10.2013
comment
@Ingo Думаю, это будет работа JIT. Да, он может внутренне преобразовывать между x = x + 1 для использования iinc, а также x = x + n для использования iinc с n в качестве второго параметра. Но дело не в этом. Поправьте меня, если я где-то ошибаюсь. - person Rohit Jain; 23.10.2013
comment
@RohitJain - Дело не в том, что вы совершенно неправы, но вы обобщаете эмпирический результат одной компиляции с одним компилятором. И тем не менее, можно прийти к выводу, просто подумав: два выражения действительно имеют разную семантику, следовательно, байт-код должен отличаться, кроме maqybe в случаях, когда выражения написаны только для побочного эффекта. Но, как вы продемонстрировали, существует как минимум 1 компилятор, который даже в этом случае генерирует другой код. - person Ingo; 23.10.2013
comment
@Ingo Ну, тогда понять это для разных компиляторов совершенно недосягаемо;) Я всегда думал, что компиляторы, реализованные для Java, должны следовать инструкциям JVM. Но опять же вы правы в том, что ничто не мешает компилятору использовать другой набор инструкций из доступного набора для реализации той же операции. - person Rohit Jain; 23.10.2013
comment
@RohitJain Разве iinc не инструкция JVM? Поэтому я не понимаю, как компилятор не выполняет инструкции JVM. Где сказано, что определенные выражения должны компилироваться в определенные байт-коды? Кстати, я читал, что компилятор Oracle (Sun) намеренно не выполняет оптимизацию, оставляя это JIT. Это объясняет различный байт-код, поскольку компилятор должен учитывать особый случай, когда добавляется 1. - person Ingo; 23.10.2013
comment
@Ingo (для первого заявления) Да. Я сказал только это. Возможно, это был неправильно оформленный комментарий. Да, компилятор может использовать любую инструкцию для представления определенной операции. - person Rohit Jain; 23.10.2013
comment
Я только что протестировал его с помощью eclipse, и он произвел iinc для обоих выражений. Итак, я нашел один компилятор, производящий такие же инструкции. - person Holger; 23.10.2013

Два выражения x++ и x=x+1 не дадут одинаковый результат, ваш профессор ошибается (или вы перепутали это с ++x, который снова отличается). Чтобы увидеть это

void notthesame() {
    int i = 0;
    System.out.println(i = i + 1);
    i = 0;
    System.out.println(i++);
    System.out.println("See?");
}

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

person Ingo    schedule 22.10.2013
comment
Люди, вы можете 100 раз отрицать меня, это все равно не то же самое, поэтому байт-код даже не имеет значения. @sdasdadas Да, байт-код другой, по крайней мере, в этом случае. - person Ingo; 23.10.2013
comment
Байт-код отличается, даже если он используется так, что семантика одинакова (читайте: в отдельном заявлении). Это было бы разумным невысказанным предположением. Можно отметить, что в целом у них разная семантика, но это само по себе не дает ответа на вопрос. - person ; 23.10.2013
comment
@buzzsawddog Я сделал! Как два вычисления с разными результатами могут иметь один и тот же байт-код? Это невозможно. Следовательно. - person Ingo; 23.10.2013
comment
Основываясь на вашей новой редакции, можете ли вы объяснить, как ++ x семантически отличается от i = i + 1? - person Cruncher; 23.10.2013
comment
@Cruncher Я мог бы и сделал бы, если бы я не получил уже столько голосов против, потому что якобы не отвечал на вопрос. - person Ingo; 23.10.2013
comment
@Ingo Конечно, эти два утверждения не одно и то же. Вы доказываете это тем, что x = x + 1 - это утверждение, а x++ - выражение. Я предполагаю, что OP просто обеспокоен изменениями значения x после этой операции, а не в зависимости от контекста, в котором они могут использоваться. - person Rohit Jain; 23.10.2013
comment
@RohitJain К сожалению, присвоение является выражением в Java. Однако я согласен с остальной частью вашего обоснования. - person ; 23.10.2013