Nota : in origine ho inserito il codice C # in questa risposta a scopo illustrativo, poiché C # consente di passare int
parametri tramite riferimento con la ref
parola chiave. Ho deciso di aggiornarlo con l'effettivo codice Java legale utilizzando la prima MutableInt
classe che ho trovato su Google per una sorta di approssimazione di ciò che ref
fa in C #. Non posso davvero dire se questo aiuta o fa male la risposta. Dirò che personalmente non ho fatto molto sviluppo Java; quindi, per quanto ne so, potrebbero esserci modi molto più idiomatici per illustrare questo punto.
Forse se scriviamo un metodo per fare l'equivalente di ciò x++
che lo renderà più chiaro.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
Giusto? Incrementa il valore passato e restituisce il valore originale: questa è la definizione dell'operatore di postincremento.
Ora vediamo come si comporta questo comportamento nel tuo codice di esempio:
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)
fa cosa? Incrementi x
, si. E quindi restituisce ciò che x
era prima dell'incremento . Questo valore restituito viene quindi assegnato a x
.
Quindi l'ordine dei valori assegnati x
è 0, quindi 1, quindi 0.
Questo potrebbe essere ancora più chiaro se riscriviamo quanto sopra:
MutableInt x = new MutableInt(); // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp; // Now x is 0 again.
La tua fissazione sul fatto che quando sostituisci x
sul lato sinistro del compito sopra con y
"puoi vedere che prima incrementa x, e successivamente lo attribuisce a y" mi sembra confuso. Non è x
che viene assegnato a y
; è il valore precedentemente assegnato ax
. In realtà, l'iniezione y
rende le cose non diverse dallo scenario sopra; abbiamo semplicemente ottenuto:
MutableInt x = new MutableInt(); // x is 0.
MutableInt y = new MutableInt(); // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp; // y is still 0.
Quindi è chiaro: x = x++
effettivamente non cambia il valore di x. Fa sempre in modo che x abbia i valori x 0 , quindi x 0 + 1, quindi nuovamente x 0 .
Aggiornamento : Per inciso, per non dubitare che x
venga mai assegnato a 1 "tra" l'operazione di incremento e l'assegnazione nell'esempio sopra, ho gettato insieme una rapida demo per illustrare che questo valore intermedio effettivamente "esiste", anche se sarà mai essere "visto" sul thread in esecuzione.
La demo chiama x = x++;
in loop mentre un thread separato stampa continuamente il valore di x
sulla console.
public class Main {
public static volatile int x = 0;
public static void main(String[] args) {
LoopingThread t = new LoopingThread();
System.out.println("Starting background thread...");
t.start();
while (true) {
x = x++;
}
}
}
class LoopingThread extends Thread {
public @Override void run() {
while (true) {
System.out.println(Main.x);
}
}
}
Di seguito è riportato un estratto dell'output del programma precedente. Notare il verificarsi irregolare di entrambi 1 e 0.
Avvio del thread in background ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1