В каком порядке инициализируются переменные класса Java?

недавно я столкнулся с этими вопросами и не смог найти ответ на StackOverflow;

  1. в каком порядке инициализируются переменные класса Java?
  2. и несколько связанный с этим вопрос, Может ли переупорядочение переменных изменить поведение класса?
  3. почему?

Как это было предложено на мета я опубликую свой ответ на этот вопрос.

1 ответов


в Java, переменные класса инициализируются в следующем порядке:

  1. статические переменные ваших суперклассов
  2. все статические переменные этого класса имеют значение значения по умолчанию.
  3. статические переменные и статические блоки инициализации, в порядке объявления.
  4. переменные экземпляра ваших суперклассов
  5. все переменные экземпляра этого класса устанавливаются значения по умолчанию.
  6. переменные экземпляра и блоки инициализации уровня экземпляра в порядке объявления

1 & 2 выполняются только при первом создании экземпляра класса.

Итак, учитывая следующий код:

class Test
  extends TestSuper
{
  final int ti1;
  final int ti2 = counter ++;
  { ti1 = counter ++; }
  static final int ts1;
  static final int ts2 = counter ++;
  static { ts1 = counter ++; }

  public static void main(String[] argv) {
    Test test1 = new Test();
    printTest(test1);
    Test test2 = new Test();
    printTest(test2);
  }
  private static void printTest(Test test) {
    System.out.print("ss2 = " + test.ss2);
    System.out.print(", ss1 = " + test.ss1);
    System.out.print(", ts2 = " + test.ts2);
    System.out.println(", ts1 = " + test.ts1);
    System.out.print("si2 = " + test.si2);
    System.out.print(", si1 = " + test.si1);
    System.out.print(", ti2 = " + test.ti2);
    System.out.println(", ti1 = " + test.ti1);
    System.out.println("counter = " + test.counter);
  }
}

class TestSuper
{
  static int counter = 0;
  final int si1;
  final int si2 = counter ++;
  { si1 = counter ++; }
  static final int ss1;
  static final int ss2 = counter ++;
  static { ss1 = counter ++; }
}

затем мы получаем следующий вывод:

ss2 = 0, ss1 = 1, ts2 = 2, ts1 = 3
si2 = 4, si1 = 5, ti2 = 6, ti1 = 7
counter = 8
ss2 = 0, ss1 = 1, ts2 = 2, ts1 = 3
si2 = 8, si1 = 9, ti2 = 10, ti1 = 11
counter = 12

из этого вывода видно, что поля инициализируются в порядке, указанном в списке.

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

например, если три строки:

  static final int ss1;
  static final int ss2 = counter ++;
  static { ss1 = counter ++; }

несколько изменен на:

  static final int ss1;
  static { ss1 = counter ++; }
  static final int ss2 = counter ++;

тогда выход изменится на:

ss2 = 1, ss1 = 0, ts2 = 2, ts1 = 3
si2 = 4, si1 = 5, ti2 = 6, ti1 = 7
counter = 8

то есть ss2 и ss1 изменит значения.

причина этого в том, что это поведение указано в Спецификация Языка Java.