2013年4月30日火曜日

[Java]static initializerの初期化タイミング

static initializerは便利ですが、思わぬ落とし穴があります。それは実行タイミングです。 たとえば、以下のようなコードがあった時、static initializerはどこで実行されるでしょう?
public static void main(String[] args) {

    System.out.println("0000");
    String aaa = StaticInitClass.aaa;
    System.out.println("1111");
    String bbb = StaticInitClass.bbb;
    System.out.println("2222");
    new StaticInitClass();

}

static class BaseStaticInitClass {
    public static String aaa = "aaa";

}

static class StaticInitClass extends BaseStaticInitClass {

    public static String bbb = "bbb";

    static {
        System.out.println("StaticInitClass{}1");
    }

    static {
        System.out.println("StaticInitClass{}2");
    }

    StaticInitClass() {
        System.out.println("StaticInitClass()");
    }
}

■実行結果は以下の通り。
0000
1111
StaticInitClass{}1
StaticInitClass{}2
2222
StaticInitClass()

「String aaa = StaticInitClass.aaa;」の時点でstatic initializerが実行されてほしいんですが、実行されません。 これは、StaticInitClassの親クラスBaseStaticInitClass へのアクセスであり、StaticInitClassに対しての操作ではありません。 そのため、static initializerは呼び出されないのです。

私は、singletonのインスタンスBaseStaticInitClass相当のクラスに隠ぺいしようとして、static initializerが呼ばれず、NPEという残念な結果になりました。
というような感じでにstaticな処理を隠ぺいしようとした場合、注意が必要です。

0 件のコメント: