Почему 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.