Uwaga : pierwotnie opublikowałem kod C # w tej odpowiedzi w celach ilustracyjnych, ponieważ C # umożliwia przekazywanie intparametrów przez odniesienie do refsłowa kluczowego. Postanowiłem zaktualizować go o rzeczywisty legalny kod Java, używając pierwszej MutableIntklasy, którą znalazłem w Google, aby w przybliżeniu to, co refrobi w C #. Naprawdę nie wiem, czy to pomaga, czy boli odpowiedź. Powiem, że osobiście nie zrobiłem tyle rozwoju Java; więc o ile wiem, można zilustrować ten idiomatyczny sposób.
Być może, jeśli napiszemy metodę równoważną temu, co x++to uczyni, będzie to jaśniejsze.
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}
Dobrze? Zwiększ przekazaną wartość i zwróć pierwotną wartość: taka jest definicja operatora poinkrementacji.
Zobaczmy teraz, jak wygląda to zachowanie w przykładowym kodzie:
MutableInt x = new MutableInt();
x = postIncrement(x);
postIncrement(x)robi co? Przyrosty x, tak. A potem zwraca to, co x było przed przyrostem . Ta zwracana wartość jest następnie przypisywana do x.
Tak więc kolejność przypisanych wartości xto 0, następnie 1, a następnie 0.
To może być jeszcze jaśniejsze, jeśli przepiszemy powyższe:
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.
Twoje przypuszczenie, że po zastąpieniu xpo lewej stronie powyższego zadania słowem y„widać, że najpierw zwiększa x, a później przypisuje je y”, wydaje mi się mylące. Nie xprzypisuje się tego y; jest to wartość poprzednio przypisanax . Naprawdę, wstrzykiwanie ynie różni się niczym od powyższego scenariusza; po prostu mamy:
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.
Jest więc jasne: x = x++skutecznie nie zmienia wartości x. Zawsze powoduje, że x ma wartości x 0 , następnie x 0 + 1, a następnie x 0 ponownie.
Aktualizacja : Nawiasem mówiąc, aby nie wątpić, że xkiedykolwiek zostanie przypisane do 1 „pomiędzy” operacją przyrostową a przypisaniem w powyższym przykładzie, zrzuciłem szybkie demo, aby zilustrować, że ta wartość pośrednia rzeczywiście „istnieje”, chociaż będzie nigdy nie będzie „widoczny” w wątku wykonującym.
Demo wywołuje x = x++;pętlę, podczas gdy oddzielny wątek ciągle drukuje wartość xna konsoli.
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);
}
}
}
Poniżej znajduje się fragment wyników powyższego programu. Zwróć uwagę na nieregularne występowanie zarówno 1, jak i 0.
Rozpoczynam wątek w tle ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1