Nota : Originalmente publiqué el código C # en esta respuesta con fines ilustrativos, ya que C # le permite pasar int
parámetros por referencia con la ref
palabra clave. Decidí actualizarlo con un código Java legal real usando la primera MutableInt
clase que encontré en Google para aproximarme a lo que ref
hace en C #. Realmente no puedo decir si eso ayuda o perjudica la respuesta. Diré que personalmente no he hecho tanto desarrollo de Java; por lo que sé, podría haber formas mucho más idiomáticas de ilustrar este punto.
Quizás si escribimos un método para hacer el equivalente de lo x++
que hace, esto lo aclarará más.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
¿Derecha? Incremente el valor pasado y devuelva el valor original: esa es la definición del operador postincremento.
Ahora, veamos cómo se desarrolla este comportamiento en su código de ejemplo:
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)
que hace Incrementos x
, sí. Y luego devuelve lo que x
estaba antes del incremento . Este valor de retorno se asigna a x
.
Entonces, el orden de los valores asignados x
es 0, luego 1, luego 0.
Esto podría ser más claro aún si reescribimos lo anterior:
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.
Su fijación en el hecho de que cuando reemplaza x
en el lado izquierdo de la asignación anterior con y
"puede ver que primero incrementa x, y luego lo atribuye a y" me confunde. No es a lo x
que se le está asignando y
; es el valor anteriormente asignadox
. Realmente, la inyección y
hace que las cosas no sean diferentes del escenario anterior; simplemente tenemos:
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.
Entonces está claro: x = x++
efectivamente no cambia el valor de x. Siempre hace que x tenga los valores x 0 , luego x 0 + 1 y luego x 0 nuevamente.
Actualización : Incidentalmente, para que no dude que x
alguna vez se asigna a 1 "entre" la operación de incremento y la asignación en el ejemplo anterior, he preparado una demostración rápida para ilustrar que este valor intermedio realmente "existe", aunque lo hará nunca ser "visto" en el hilo de ejecución.
La demostración llama x = x++;
en un bucle mientras un hilo separado imprime continuamente el valor de x
en la consola.
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);
}
}
}
A continuación se muestra un extracto de la salida del programa anterior. Observe la ocurrencia irregular de 1s y 0s.
Iniciando hilo de fondo ...
0 0
0 0
1
1
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
1
0 0
1