Давайте сделаем небольшой анализ и покопаемся в байт-коде обоих подходов.
public class Main {
public static void main(String[] args) {
Main test = new Main();
Integer integer = 4;
System.out.println(integer);
test.change(integer);
System.out.println(integer);
}
public void change(Integer integer) {
integer++;
}
}
Байт-код для change
метода:
public change(Ljava/lang/Integer;)V
L0
LINENUMBER 14 L0
ALOAD 1
ASTORE 2
ALOAD 1
INVOKEVIRTUAL java/lang/Integer.intValue ()I // gets value of wrapped int
ICONST_1 // load 1 into stack
IADD // add 1 to your value
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; // return
DUP
ASTORE 1
ASTORE 3
ALOAD 2
POP
Как видите, значение увеличивается и ... и теряется, потому что оно не было возвращено. Поэтому нам нужно вернуть это значение, чтобы получить результат, верно?
Кто-то может подумать, что вывод для следующего кода будет 4, 5
:
public class Main {
public static void main(String[] args) {
Main test = new Main();
Integer integer = 4;
System.out.println(integer);
Integer integerNew = test.change(integer);
System.out.println(integerNew);
}
public Integer change(Integer integer) {
return integer++;
}
}
Вывод 4, 4
.
Почему? Потому что это постинкремент . Вы увеличили новый Integer
и вернули старый. Анализ байт-кода подтверждает это:
public change(Ljava/lang/Integer;)Ljava/lang/Integer;
L0
LINENUMBER 14 L0
ALOAD 1
ASTORE 2 // store the copy of the first Integer (4)
ALOAD 1 //
INVOKEVIRTUAL java/lang/Integer.intValue ()I // get value of first
ICONST_1 // load 1
IADD // add 1
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; // get modified value Integer (5)
DUP
ASTORE 1 // save it
ASTORE 3
ALOAD 2 // load the copy Integer (4)
ARETURN // return it
Итак, мы видим, что значение Integer
было увеличено и ... и снова потеряно, потому что мы вернули значение в состоянии до того, как оно было увеличено.
Предварительное увеличение - это то, что мы ищем:
public Integer change(Integer integer) {
return ++integer;
}
И байт-код:
public change(Ljava/lang/Integer;)Ljava/lang/Integer;
L0
LINENUMBER 14 L0
ALOAD 1 // Integer (4)
INVOKEVIRTUAL java/lang/Integer.intValue ()I
ICONST_1 // load 1
IADD // becomes Integer (5)
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
DUP
ASTORE 1 // save it
ARETURN // return Integer (5)
Значение было увеличено до того, как оно было возвращено, и мы можем принять его.
Анализ последнего случая:
public class Main {
public static void main(String[] args) {
Main test = new Main();
MyInteger myInteger = new MyInteger();
myInteger.x = 4;
System.out.println(myInteger.x);
test.change(myInteger);
System.out.println(myInteger.x);
}
public void change(MyInteger integer) {
integer.x++;
}
}
class MyInteger {
Integer x;
}
и его байт-код:
public change(Lcom/test/MyInteger;)V
L0
LINENUMBER 15 L0
ALOAD 1
ASTORE 2
ALOAD 2
GETFIELD com/test/MyInteger.x : Ljava/lang/Integer; // get Integer (4)
ASTORE 3 // store copy of Integer value (4)
ALOAD 2
ALOAD 2
GETFIELD com/test/MyInteger.x : Ljava/lang/Integer; // get Integer (4)
INVOKEVIRTUAL java/lang/Integer.intValue ()I
ICONST_1
IADD // add 1
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
DUP_X1
PUTFIELD com/test/MyInteger.x : Ljava/lang/Integer; // PUT Integer (5) BACK!
ASTORE 4
ALOAD 3
POP
Как видите, начиная с строки PUTFIELD
экземпляр MyInteger
начинает содержать ссылку на Integer
со значением 5
.
Надеюсь, что это поможет вам понять более подробно о теме.