Diamo uno sguardo al bytecode del seguente programma:
package A;
public class Test
{
public static void main(String[] args)
{
int a = 1;
a += (a = 2);
}
}
Abbiamo solo bisogno di eseguire questo comando:
javap -c Test.class
per ottenere il seguente bytecode:
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
}
Spiegazione:
Ci concentrarsi solo sulle due linee all'interno del principale metodo:
int a = 1;
a += (a = 2);
[int a = 1;
comincia qui]
0: iconst_1
- Spinge int
1
nello stack .
-------------
| |
-------------
| |
-------------
| 1 |
-------------
STACK
1: istore_1
- botti valore int dallo stack a
variable 1
(variable 1
rappresenta a
)
-------------
| | variable 1
------------- --------------
| | | 1 |
------------- --------------
| |
-------------
STACK
[int a = 1;
finiture qui]
[a += (a = 2);
comincia qui]
2: iload_1
- carica un valore intero da locale
variable 1
e spinge in pila.
-------------
| | variable 1
------------- --------------
| | | |
------------- --------------
| 1 |
-------------
STACK
3: iconst_2
- Spinge int
2
nello stack.
-------------
| | variable 1
------------- --------------
| 2 | | |
------------- --------------
| 1 |
-------------
STACK
4: dup
- duplicare il valore in cima alla pila.
-------------
| 2 | variable 1
------------- --------------
| 2 | | |
------------- --------------
| 1 |
-------------
STACK
5: istore_1
- botti valore int dalla pila a
variable 1
.
-------------
| | variable 1
------------- --------------
| 2 | | 2 |
------------- --------------
| 1 |
-------------
STACK
6: iadd
- aggiunge i primi due valori insieme.
-------------
| | variable 1
------------- --------------
| | | 2 |
------------- --------------
| 3 |
-------------
STACK
7: istore_1
- botti valore int dalla pila a
variable 1
.
-------------
| | variable 1
------------- --------------
| | | 3 |
------------- --------------
| |
-------------
STACK
[a += (a = 2);
finiture qui]
8: return
- il principale metodo restituisce.
Conclusione:
a = a + (a = 2)
viene fatto attraverso diverse operazioni. 2: iload_1
viene eseguito come primo comando di a += (a = 2);
che legge il primo operando dell'equazione a = a + (a = 2)
e spinge nello stack.
Successivamente, vengono eseguiti 3: iconst_2
e 4: dup
che sostanzialmente spingono int 2
due volte nello stack; uno per caricarlo su a
e l'altro come secondo operando. Successivamente viene eseguito 5: istore_1
che sta caricando 2
in a
(a = 2
).
Infine, 6: iadd
e 7: istore_1
vengono eseguiti dove 6: iadd
aggiunge il primo operando e il secondo operando e spinge il risultato nello stack, e 7: istore_1
schiocca il risultato e carica nella a
.
Per semplicità, diamo un rapido sguardo a questo codice:
int a = 1;
int b = 3;
a += b;
e qui è il suo bytecode:
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
}
Come si può vedere, lo fa semplicemente il seguente:
- Carichi int
1
in a
.
- Carichi int
3
in b
.
- Spinge
a
quindi b
sullo stack.
- Esegue l'aggiunta su di loro e spinge il risultato in pila.
- Carica il risultato dallo stack e lo memorizza in
a
.
correlati: http://stackoverflow.com/questions/11324850/why-swapping-integer-variable-by-xor-doesnt-work-in-a-single-line/11325458 – nhahtdh
Idem come 'int a = 1; int tmpvar = (a = 2); a + = tmpvar; ' –
Si traduce in' a = a + (a = 2); ', e gli operandi vengono valutati da sinistra a destra. –