Java : 初期化ブロック

気になったので、調査してみました。

public class Main {
  static class Test {
    { num = 0; /*p(num);*/} //コンパイルエラー
    int num = num();
    Test() { num = 1; p(num);}
    { num = 2; p(num);}
    int num() { p(3); return 3;}
    { num = 4; p(num);}
  }
  public static void main(String[] args) {
    Test test = new Test();
    System.out.println(test.num);
  }
  static void p(int num) { System.out.println(num);}
}

3行目のコメントアウトは、「順方向参照が不正です。」というエラーメッセージでコンパイルできなかったところです。
実行結果は、

3
2
4
1
1

ということで、まず、フィールドの初期化メソッドが呼ばれて、次に初期化ブロックが上から順に呼ばれ、最後にコンストラクタが呼ばれているみたい。
じゃあ、ということで、こんな風に追加すると、

public class Main {
  static class Test {
    { num = 0; /*p(num);*/} //コンパイルエラー
    int num3 = num3();
    int num = num();
    Test() { num = 1; p(num);}
    { num = 2; p(num);}
    int num2() { num = 5; p(num); return num;}
    int num() { p(3); return 3;}
    { num = 4; p(num);}
    int num2 = num2();
    int num3() { num = 6; p(num); return num;}
  }
  public static void main(String[] args) {
    Test test = new Test();
    System.out.println(test.num);
  }
  static void p(int num) { System.out.println(num);}
}

結果は、

6
3
2
4
5
1
1

フィールドの初期化メソッドは、一番最初に上から順に呼ばれている。
サブクラスはどうかと確認してみると、

public class Main {
  static class Test {
    int num = num();
    Test() { num = 1; p(num);}
    { num = 2; p(num);}
    int num() { p(3); return 3;}
    { num = 4; p(num);}
  }
  static class SubTest extends Test {
    { num = 5; p(num);}
  }
  public static void main(String[] args) {
    Test test = new SubTest();
    System.out.println(test.num);
  }
  static void p(int num) { System.out.println(num);}
}
3
2
4
1
5
5

サブクラスの初期化ブロックは、一番最後に呼ばれている。
ふむ。納得。