Hinweis : Ursprünglich habe ich in dieser Antwort zur Veranschaulichung C # -Code angegeben, da Sie mit C # int
Parameter als Referenz mit dem ref
Schlüsselwort übergeben können. Ich habe beschlossen, es mit tatsächlichem legalem Java-Code zu aktualisieren, indem MutableInt
ich die erste Klasse verwende, die ich bei Google gefunden habe, um ungefähr zu wissen, was ref
in C # funktioniert. Ich kann nicht wirklich sagen, ob das hilft oder die Antwort verletzt. Ich werde sagen, dass ich persönlich nicht so viel Java-Entwicklung gemacht habe; Soweit ich weiß, könnte es viel idiomatischere Möglichkeiten geben, diesen Punkt zu veranschaulichen.
Wenn wir eine Methode aufschreiben, die das Äquivalent zu dem x++
tut, was sie tut, wird dies möglicherweise klarer.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
Recht? Inkrementieren Sie den übergebenen Wert und geben Sie den ursprünglichen Wert zurück: Dies ist die Definition des Nachinkrementierungsoperators.
Lassen Sie uns nun sehen, wie sich dieses Verhalten in Ihrem Beispielcode auswirkt:
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)
macht was? Inkremente x
, ja. Und dann gibt , was x
war vor dem Zuwachs . Dieser Rückgabewert wird dann zugewiesen x
.
Die Reihenfolge der zugewiesenen Werte x
ist also 0, dann 1, dann 0.
Dies könnte noch deutlicher werden, wenn wir das Obige neu schreiben:
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.
Ihre Fixierung auf die Tatsache, dass, wenn Sie x
auf der linken Seite der obigen Zuordnung durch y
"Sie können sehen, dass es zuerst x erhöht und später y zuschreibt", mich verwirrt erscheinen. Es ist nicht x
das, was zugewiesen wird y
; Dies ist der Wert, der zuvor zugewiesen wurdex
. Das Injizieren unterscheidet y
die Dinge nicht von dem obigen Szenario. Wir haben einfach:
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.
Es ist also klar: x = x++
Ändert den Wert von x effektiv nicht. Es bewirkt immer, dass x die Werte x 0 , dann x 0 + 1 und dann wieder x 0 hat.
Update : Damit Sie nicht bezweifeln, dass x
zwischen dem Inkrementierungsvorgang und der Zuweisung im obigen Beispiel jemals 1 "zugewiesen" wird, habe ich eine kurze Demo zusammengestellt, um zu veranschaulichen, dass dieser Zwischenwert tatsächlich "existiert", obwohl dies der Fall ist Niemals auf dem ausführenden Thread "gesehen" werden.
Die Demo ruft x = x++;
in einer Schleife auf, während ein separater Thread den Wert von kontinuierlich x
an die Konsole druckt .
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);
}
}
}
Unten finden Sie einen Auszug aus der Ausgabe des obigen Programms. Beachten Sie das unregelmäßige Auftreten von Einsen und Nullen.
Hintergrund-Thread starten ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1