Порядок выполнения определяется из супер- и подкласса и внутри классов, сначала выполняется статическая инициализация переменных, прежде чем исполняются блоки-инициализаторы. Это дает следующий порядок:
class X {
int m = 1111; // 1st point visited
// This is X's initializer block:
{
m = m++; // 2nd point visited: m's value is not changed, read below
System.out.println(m);
}
}
class Y extends X {
// This is Y's initializer block:
{
System.out.println(methodOfY()); // 3rd and 5th point visited:
// 2220 is printed after
// methodOfY() has been evaluated
}
int methodOfY() {
return m-- + --m; // 4th point visited: m-- = 1111 (m = 1110),
// --m = 1109 (m = 1109), therefore 2220 is
// returned
}
}
public class MainClass {
public static void main(String[] args) {
Y y = new Y();
}
}
Теперь оператору до и после операции. Вы можете реализовать их «вручную» , чтобы понять их поведение:
public class PrePostIncrement {
int value;
public PrePostIncrement(int value) {
this.value = value;
}
public int preIncrement() {
this.value = this.value + 1;
return (this.value);
}
public int postIncrement() {
int result = this.value;
this.value = this.value + 1;
return (result);
}
public static void main(String... args) {
PrePostIncrement test = new PrePostIncrement(1111);
int newValue = test.postIncrement();
System.out.println(newValue);
}
}
Как вы видите, значение, возвращаемое postIncrement()
является 1111
. Это будет новое значение, присвоенное m
в блоке инициализации X
. Таким образом, m
будет иметь значение 1112
только для краткости.
Поскольку я не ожидаю, что вы просто поверьте, я написал код, показывающий именно такое поведение:
public class Main {
public static volatile int x = 0;
public static volatile boolean running = true;
public static void main(String... args) {
Thread observer = new Thread(() -> {
while (true) {
int x = Main.x;
System.out.println("Observer observed: " + x);
if (0 != x) {
break;
}
}
Main.running = false;
});
observer.start();
while (running) {
Main.x = Main.x++;
}
System.out.println(Main.x);
}
}
Как вы видите, observer
«s единственная цель заключается в печати x
» значение s, пока он видит x
значение 1
. Основной поток продолжает выполнять x = x++;
до observer
видел одно изменение в значении x
. Затем будет напечатано окончательное значение x
. Обратите внимание, что эта программа должна запускаться в реальной многоядерной системе, иначе она может работать в бесконечном цикле.
В моей системе обычно я получаю от одного до шести итераций observer
до тех пор, пока изменения не будут видны. Конечное значение x
, однако, всегда будет '0'.
P.S .: Добро пожаловать в мир Java-параллелизма. Если нужно написать приложение с несколькими потоками, для которого требуется одновременный доступ к x
, можно было бы определить x
как AtomicInteger
и использовать методы int incrementAndGet()
(вместо ++x
) и int getAndIncrement()
(вместо ++x
). Эти методы гарантируют, что промежуточные значения x
не видны другим потокам.
Пожалуйста, никогда не делать такие вещи. ++i
и i++
- это языковые конструкции и очень оптимизируются компилятором. Это только для того, чтобы продемонстрировать свое поведение.
Вполне возможно, что даже на многоядерной системе эта программа работает в бесконечном контуре, но программа прекращает almost surely. Рассуждение состоит в том, что вероятность observer
, видящая x
, как 0
равна < 1 и что-то < 1 до силы n для n к бесконечности 0.
Примечание: 'm = m ++' ничего не делает. –
Из-за порядка выполнения: сначала инициализируется переменная 'X' (' m = 1111'), тогда выполняется инициализационный блок 'X' '(' m = m ++; System.out.println (1111); ', 'm = m ++;' не изменяет значение 'm', тогда выполняется блок инициализации' Y' '('System.out.println (m-- + --m);', который будет '2200 '). – Turing85
Какой результат вы ожидали? – 4castle