Давайте посмотрим на байткод следующей программе:
package A;
public class Test
{
public static void main(String[] args)
{
int a = 1;
a += (a = 2);
}
}
Нам просто нужно запустить эту команду:
javap -c Test.class
получить следующий байт-код:
public class A.Test {
public A.Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iload_1
3: iconst_2
4: dup
5: istore_1
6: iadd
7: istore_1
8: return
}
Объяснение:
Мы сосредоточимся только на двух линиях внутри основного метода:
int a = 1;
a += (a = 2);
[int a = 1;
начинается здесь]
0: iconst_1
-------------
| |
-------------
| |
-------------
| 1 |
-------------
STACK
1: istore_1
- Попс INT значение из стека
variable 1
(variable 1
представляет a
)
-------------
| | variable 1
------------- --------------
| | | 1 |
------------- --------------
| |
-------------
STACK
[int a = 1;
заканчивается здесь]
[a += (a = 2);
начинается здесь]
2: iload_1
- Загружает целочисленное значение из локального
variable 1
и помещает его в стек.
-------------
| | variable 1
------------- --------------
| | | |
------------- --------------
| 1 |
-------------
STACK
3: iconst_2
-------------
| | variable 1
------------- --------------
| 2 | | |
------------- --------------
| 1 |
-------------
STACK
4: dup
- дублировать значение на вершине стека.
-------------
| 2 | variable 1
------------- --------------
| 2 | | |
------------- --------------
| 1 |
-------------
STACK
5: istore_1
- Pops INT значение из стека в
variable 1
.
-------------
| | variable 1
------------- --------------
| 2 | | 2 |
------------- --------------
| 1 |
-------------
STACK
6: iadd
- добавляет два значения вместе.
-------------
| | variable 1
------------- --------------
| | | 2 |
------------- --------------
| 3 |
-------------
STACK
7: istore_1
- Pops INT значение из стека в
variable 1
.
-------------
| | variable 1
------------- --------------
| | | 3 |
------------- --------------
| |
-------------
STACK
[a += (a = 2);
заканчивается здесь]
8: return
- Основной метод возвращает значение.
Вывод:
a = a + (a = 2)
сделано несколько операций. 2: iload_1
выполняется как первая команда a += (a = 2);
, которая считывает первый операнд уравнения a = a + (a = 2)
и толкает его в стек.
Далее выполняются 3: iconst_2
и 4: dup
, которые в основном нажимают int 2
два раза на стек; один для загрузки его в a
, а второй в качестве второго операнда. После этого выполняется 5: istore_1
, которое загружается 2
в a
(a = 2
).
Наконец, 6: iadd
и 7: istore_1
выполняются где 6: iadd
добавляет первый операнд и второй операнд и помещает результат в стек, и 7: istore_1
выскакивает результат и загружает его в a
.
Для простоты, давайте иметь быстрый взгляд на этот код:
int a = 1;
int b = 3;
a += b;
и вот его байткодом:
public class A.Test {
public A.Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_1
8: return
}
Как вы можете видеть, это просто делает следующее:
- Грузы int
1
в a
.
- Грузы int
3
в b
.
- Толкает
a
, затем b
в стек.
- Выполняет добавление на них и толкает результат на стек.
- Восстанавливает результат из стека и сохраняет его в
a
.
Связанный: http://stackoverflow.com/questions/11324850/why-swapping-integer-variable-by-xor-doesnt-work-in-a-single-line/11325458 – nhahtdh
То же, что 'Int А = 1; int tmpvar = (a = 2); a + = tmpvar; ' –
Он переводится в' a = a + (a = 2); ', а операнды оцениваются слева направо. –