2016-10-30 7 views
-3

Я немного растерялся, почему я поставил мне значение m = 1111 ??? вот код:Почему результат показан так? java

class X 
{ 
    int m = 1111; 

    { 
     m = m++; 

     System.out.println(m); 
    } 
} 

class Y extends X 
{ 
    { 
     System.out.println(methodOfY()); 
    } 

    int methodOfY() 
    { 
     return m-- + --m; 
    } 
} 

public class MainClass 
{ 
    public static void main(String[] args) 
    { 
     Y y = new Y(); 
    } 
} 

могли бы вы объяснить, почему выход будет, как это?

+4

Примечание: 'm = m ++' ничего не делает. –

+0

Из-за порядка выполнения: сначала инициализируется переменная 'X' (' m = 1111'), тогда выполняется инициализационный блок 'X' '(' m = m ++; System.out.println (1111); ', 'm = m ++;' не изменяет значение 'm', тогда выполняется блок инициализации' Y' '('System.out.println (m-- + --m);', который будет '2200 '). – Turing85

+0

Какой результат вы ожидали? – 4castle

ответ

0

Порядок выполнения определяется из супер- и подкласса и внутри классов, сначала выполняется статическая инициализация переменных, прежде чем исполняются блоки-инициализаторы. Это дает следующий порядок:

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.

+0

Спасибо @ Turing85 –

 Смежные вопросы

  • Нет связанных вопросов^_^