Nota : Originalmente, eu publiquei o código C # nesta resposta para fins de ilustração, pois o C # permite que você passe intparâmetros por referência com a refpalavra - chave. Decidi atualizá-lo com código Java legal real, usando a primeira MutableIntclasse que encontrei no Google para aproximar o que refé feito em c #. Não sei dizer se isso ajuda ou prejudica a resposta. Eu direi que pessoalmente não fiz tanto desenvolvimento em Java; então, pelo que sei, poderia haver muito mais maneiras idiomáticas para ilustrar esse ponto.
Talvez se escrevermos um método para fazer o equivalente ao que x++isso tornará isso mais claro.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
Direita? Incremente o valor passado e retorne o valor original: essa é a definição do operador pós-incremento.
Agora, vamos ver como esse comportamento se desenrola no seu código de exemplo:
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)Faz o que? Incrementos x, sim. E então retorna o que x estava antes do incremento . Esse valor de retorno é atribuído a x.
Portanto, a ordem dos valores atribuídos xé 0, depois 1 e 0.
Isso pode ser mais claro ainda se reescrevermos o acima:
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.
Sua fixação no fato de que, quando você substitui xno lado esquerdo da atribuição acima por y", você pode ver que ela primeiro incrementa xe depois atribui a y" me parece confuso. Não é isso xque está sendo atribuído y; é o valor anteriormente atribuídox . Realmente, injetar ytorna as coisas não diferentes do cenário acima; nós simplesmente temos:
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.
Portanto, é claro: x = x++efetivamente não altera o valor de x. Sempre faz com que x tenha os valores x 0 , x 0 + 1 e x 0 novamente.
Atualização : Aliás, para que você não duvide que xseja atribuído a 1 "entre" a operação de incremento e a atribuição no exemplo acima, juntei uma demonstração rápida para ilustrar que esse valor intermediário realmente "existe", embora nunca seja "visto" no thread em execução.
A demo chama x = x++;em loop enquanto um thread separado imprime continuamente o valor de xpara o 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);
}
}
}
Abaixo está um trecho da saída do programa acima. Observe a ocorrência irregular de 1s e 0s.
Iniciando o encadeamento em segundo plano ...
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