Remarque : à l'origine, j'ai publié du code C # dans cette réponse à des fins d'illustration, car C # vous permet de passer des int
paramètres par référence avec leref
mot clé. J'ai décidé de le mettre à jour avec le code Java légal réel en utilisant la première MutableInt
classe que j'ai trouvée sur Google pour trier approximativement ce qui se ref
passe en C #. Je ne peux pas vraiment dire si cela aide ou nuit à la réponse. Je dirai que personnellement, je n'ai pas fait beaucoup de développement Java; donc pour tout ce que je sais, il pourrait y avoir des façons beaucoup plus idiomatiques pour illustrer ce point.
Peut-être que si nous écrivons une méthode pour faire l'équivalent de ce x++
que cela fera, cela sera plus clair.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
Droite? Incrémentez la valeur passée et retournez la valeur d'origine: c'est la définition de l'opérateur post-incrément.
Voyons maintenant comment se comporte ce comportement dans votre exemple de code:
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)
Fait quoi? Incréments x
, oui. Et puis retourne ce qui x
était avant l'incrément . Cette valeur de retour est ensuite affectée à x
.
Ainsi, l'ordre des valeurs attribuées à x
est 0, puis 1, puis 0.
Cela pourrait être encore plus clair si nous réécrivons ce qui précède:
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.
Votre fixation sur le fait que lorsque vous remplacez x
à gauche de l'affectation ci-dessus par y
", vous pouvez voir qu'elle incrémente d'abord x, puis l'attribue à y" me semble confuse. Ce n'est pas ce x
qui est assigné à y
; il s'agit de la valeur précédemment attribuéex
. Vraiment, l'injection ne y
fait rien de différent du scénario ci-dessus; nous avons simplement:
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.
Donc, c'est clair: x = x++
effectivement ne change pas la valeur de x. Il fait toujours en sorte que x ait les valeurs x 0 , puis x 0 + 1, puis x 0 nouveau .
Mise à jour : Incidemment, de peur que vous doutiez que x
jamais soit attribué à 1 "entre" l'opération d'incrémentation et l'affectation dans l'exemple ci-dessus, j'ai rassemblé une démo rapide pour illustrer que cette valeur intermédiaire "existe" bien, bien qu'elle ne jamais être "vu" sur le fil d'exécution.
La démo appelle x = x++;
en boucle tandis qu'un thread séparé imprime en continu la valeur de x
à la 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);
}
}
}
Ci-dessous est un extrait de la sortie du programme ci-dessus. Remarquez l'occurrence irrégulière des 1 et des 0.
Démarrage du thread d'arrière-plan ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1