【Java】初期化について

はじめに

Javaのとある書籍を読んでいて、学んだことがあったので備忘録がてらエントリする。
今回は、フィールドのstatic初期化について記載する。

サンプルプログラム

今回の例では、2つのクラスを用意し、それぞれがもう片方のstatic初期化をしようとすると、どんな手順で初期化が行われるのかを記載する。

【ClassA.java

public class ClassA {
    static int x = ClassB.init();

    static int init() {
        return x;
    }
}

【ClassB.java

public class ClassB {
    static int y = ClassA.init();

    static int init() {
        return y+=10;
    }
}

このコードでやっていること

見てのとおり、各クラスのフィールドの初期化である。しかし、この場合、互いのフィールドは互いのクラスのinitメソッドを使って初期化しようとしている。この場合、互いのフィールドに格納される値は何なのだろうか。

【前提】
1. メソッド実行の前に初期化が実行されることが保障されている。
2. 初期化は1度だけ行われる。

上記前提を踏まえたうえで、処理の流れを追っていく。
今回記したコードの場合、以下の手順で処理が進む。

  1. x の値の初期化が始まる。
  2. ClassB #init() が呼ばれる。 ※呼ばれるものの、ClassB #init()は実行されない。なぜなら、ClassBの初期化がされていないから。
  3. ClassB の初期化のために、ClassA.init() が呼ばれる。
  4. ClassA #init() 内に処理が進む。xをリターンするとあるが、xはまだ初期化されていない。この場合、デフォルト値である0がリターンされる。
  5. ClassA #init() のリターン値「0」がClassB.yに格納される。つまり、「ClassB.y = 0」で初期化される。
  6. ClassBの初期化が終わったので、ClassAの初期化が可能になる。=ClassAの初期化のために呼ばれていたClassB #init()が実行される。
  7. ClassB #init() のリターン値は、ClassBのフィールド値yに10を足した値。y=0でなので、10がリターンされる。
  8. ClassA.xに、ClassB #init() のリターン値が格納される。つまり、「ClassA.x = 10」で初期化される。

まとめ

各クラスのフィールドが、互いのクラスのstaticメソッドで初期化されるときの処理を追っていった。
実際のコードでこのようなややこしい(面倒くさい)初期化をすることはそうそう無いとは思うが、初期化の順序というか、流れは知っておいて損は無いと思う。
コンストラクタや初期化ブロックといったフィールドの初期化方法がJavaには備わっている。近々これについても投稿できればと思う。

参考

DCL00-J. クラスの初期化を循環させない