Подтвердить что ты не робот

Почему поля, кажется, инициализируются перед конструктором?

public class Dog {

 public static Dog dog = new Dog();
 static final int val1 = -5;
 static int val2 = 3;
 public int val3;

 public Dog() {
      val3 = val1 + val2;
 }

public static void main(String[] args) {
    System.out.println(Dog.dog.val3);
}
}

Выходной сигнал -5

Из этого результата кажется, что инициализация val2 выполняется до завершения члена dog и его экземпляра.

Почему этот порядок выглядит следующим образом?

4b9b3361

Ответ 1

Если вы переместите экземпляр вашей собаки в конце, вы увидите, что результат будет равен -2

public class Dog {

     static final int val1 = -5;// This is final, so will be initialized at compile time 
     static int val2 = 3;
     public int val3;

     public static Dog dog = new Dog();//move to here

     public Dog() {
          val3 = val1 + val2;
     }

    public static void main(String[] args) {
        System.out.println(Dog.dog.val3);//output will be -2
    }
}

Окончательные поля (значения которых являются константами постоянной времени компиляции) сначала будут инициализированы, а затем остальные будут выполнены в текстовом порядке.

Итак, в вашем случае, когда инициализируется экземпляр собаки, static int val2 (0) еще не инициализирован, тогда как static final int val1 (- 5) делает, поскольку он является окончательным.

http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.4.2 утверждает, что:

выполнить либо инициализаторы переменной класса, либо статические инициализаторы класса или инициализаторы полей интерфейса, в текстовом порядке, как если бы они были одним блоком, , за исключением того, что конечные переменные класса и поля интерфейсов, значения которых константы времени компиляции сначала инициализируются


Обновлен новый документ

Вот версия jdk7 из http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2

Конечное поле находится на шаге 6:

Затем инициализируйте конечные переменные класса и поля интерфейсов значения которых являются постоянными выражениями времени компиляции

тогда как статическое поле находится на шаге 9:

Далее выполните либо инициализаторы переменной класса, либо статические инициализаторы класса или инициализаторы полей интерфейса, в текстовом порядке, как если бы они были одним блоком.

Ответ 2

Переменная последовательность объявлений. static final int val1 сначала инициализируется, потому что это константа. Однако static int val2 все еще 0 в момент создания public static Dog dog = new Dog();.

Ответ 3

Что происходит..

Первая строка, которая выполняется, - это public static Dog dog = new Dog();. Теперь есть две вещи, которые нужно иметь в виду.

  • final int делает его постоянной времени компиляции. Таким образом, -5 уже жестко закодирован в ваш код.

  • Выполняется вызов нового Dog() и вызывается конструктор, который устанавливает значение 0 + -5= -5.

измените val2 на final, тогда вы увидите разницу (вы получите -2 в качестве ответа.)

Примечание: статические поля инициализируются как и как они встречаются.

Ответ 4

Последовательность инициализации в вашем тесте;

  • static final int val1 = -5;//константа как статическая окончательная
  • public static Dog dog = new Dog();//тогда "собака" инициализируется, но его член val2 не был инициализирован
  • static int val2 = 3;//наконец, инициализируется 'val2'

Это изменение кода выведет -2;

public class Dog {

     //public static Dog dog = new Dog();
     static final int val1 = -5;
     static int val2 = 3;
     public int val3;
     public static Dog dog = new Dog();     //moved here

     public Dog() {
          val3 = val1 + val2;
     }


    public static void main(String[] args) {
        System.out.println(Dog.dog.val3);

    }
}

Ответ 5

Все статические переменные инициализируются в отдельном статическом конструкторе, который выполняется при загрузке классов. В том же порядке, что и в коде. Ваш пример скомпилирован примерно так:

public class Dog {

 public static Dog dog;
 static final int val1 = -5;
 static int val2;
 public int val3;

 static {
  dog = new Dog();
  val2 = 3;
 }

 public Dog() {
      val3 = val1 + val2;
 }

 public static void main(String[] args) {
     System.out.println(Dog.dog.val3);
 }
}

Вот почему имеет смысл порядок переменных класса/экземпляра. Выполнение конструктора класса происходит в конце инициализации. Константы разрешаются раньше. Для получения дополнительной информации см. Создание экземпляров нового класса.