Почему post-increment работает над классами-оболочками

Я делал обзор некоторого кода и наткнулся на экземпляр кого-то после инкрементной переменной-члена, которая была классом-оболочкой в ​​Integer. Я попробовал это сам и был искренне удивлен, что он работает.

Integer x = 0; 
System.out.print(x++ + ", ");
System.out.print(x);

Отпечатает 0, 1, а не 0, 0, как я ожидал. Я просмотрел спецификацию языка и не могу найти ничего подобного. Может ли кто-нибудь объяснить мне, почему это работает и безопасно ли оно на нескольких платформах? Я бы подумал, что это разложится на

Integer x = 0;
int temp1 = x.intValue();
int temp2 = temp1 + 1;
System.out.println(temp1);
temp1 = temp2;
System.out.println(x.intValue());

Но, видимо, есть что-то в спецификации, которые заставляют его добавлять x = temp1; до последней строки

Ответ 1

Это совершенно безопасно для использования на разных платформах. Поведение указано в §15.4.2 Спецификации языка Java (выделено мной):

Результат выражения postfix должен быть переменной типа, который является конвертируемым (§5.1.8) к числовому типу, или возникает ошибка времени компиляции.

Тип выражения postfix increment - это тип переменной. Результат выражения postfix increment не является переменной, а значением.

Во время выполнения, если оценка выражения операнда завершается внезапно, то выражение поэтапного приращения завершается внезапно по той же причине, и приращение не происходит. В противном случае значение 1 добавляется к значению переменной , и сумма сохраняется в переменной. Перед добавлением бинарное числовое продвижение (§5.6.2) выполняется по значению 1 и значению переменной. При необходимости сумма сужается сужением примитивного преобразования (§5.1.3) и/или подвергнутой конверсии бокса (§5.1.7) к типу переменной перед ее сохранением. Значение выражения postfix increment - это значение переменной перед сохранением нового значения.

EDIT Здесь более точный эквивалент того, что происходит в вашем примере кода:

Integer x = 0;
int temp = x.intValue();
x = temp + 1; // autoboxing!
System.out.println(temp + ", ");
System.out.println(x.intValue());

Ответ 2

Начиная с Java 1.5, Java выполняет автоматическую распаковку, чтобы преобразовать "типы обертки", такие как Integer, в соответствующий примитивный тип int, когда это необходимо. Тогда оператор приращения может работать с результирующим int.

Ответ 3

Это новая функция в Java 5, называемая autoboxing. Целое число преобразуется в нужное место и наоборот. То же самое относится к Float, Double, Boolean и т.д.

В то время как это удобная функция, это может привести к огромному результату, если вы не будете осторожны.

Ответ 4

Обратите внимание, что результат будет таким, как ожидалось, если операция приращения была перенесена в метод:

public void printIncrement(Integer x1) {
    System.out.print(x1++ + ", ");
}

Это потому, что Java передала копию ссылки, и теперь вы работаете с новым ссылочным объектом, x1 вместо x. Исходный объект Integer, на который указывал x, остается неизменным, а x по-прежнему указывает на него.

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

Ответ 5

Ответ сэра Тедда Хоппа очень сложен для программистов, которые программируют всего несколько лет.

Позвольте мне прояснить ваши сомнения простым образом, предположим,

    Integer x=10;
    x++;
    System.out.println(x) ;

выходной будет 11

Поскольку ++ или post или pre increment делает сложение на 1 только внутренне

т.е. x + 1 - это то, что он должен выполнить и вернуть результат в ту же переменную.

ie x=x+1;

теперь мы все знаем, что оператор + может принимать только примитивы, но x является объектом, тогда у нас есть концепция автоматической распаковки и автоматической упаковки. так выражение становится

x.intValue()+1;//step 1 auto-unboxing

x=Integer.valueOf(x.intValue()+1);//step 2 auto-boxing

Следовательно, вывод происходит как 11 после очередного шага автоматической распаковки внутри оператора println.