浅煎り珈琲 の オブジェクトの生成の抑制 にちょっと面白いのがあった.
private static final な singleton オブジェクトを lazy に初期化しようというものだ.
static final なので,クラスのロード時に初期化される必要があるが,本当に必要なときまで初期化を送らせたい.
それを実現するトリッキーな方法.
$ cat Singleton.java
class Singleton {
static{
System.out.println("Singleton loaded");
}
private Singleton(){
System.out.println("Singleton instantiation");
}
private static class SingletonOnlyOne {
static{
System.out.println("Singleton.SingletonOnlyOne loaded");
}
private static final Singleton singleton = new Singleton();
}
public static Singleton getSingleton() {
System.out.println("getSingleton");
return SingletonOnlyOne.singleton;
}
public static void main(String[] args){
System.out.println(getSingleton());
}
}
$ javac Singleton.java
$ java Singleton
Singleton loaded
getSingleton
Singleton.SingletonOnlyOne loaded
Singleton instantiation
Singleton@131f71a
こんな感じ.インナークラス(static が付いているから正式にはインナークラスじゃないけど)からアウタークラスのコンストラクタを呼び出す.インナークラスはアウターのロード時にはロードされない.getSingleton メソッド内でインナークラスの private static final なフィールドを参照するときに始めてインナークラスがロードされ,singleton オブジェクトが初期化される.
こういう要求が本当にあるかは微妙.だって,getSingleton 呼び出しで初めてシングルトンなクラスがロードされることが多いだろう.
更に,別の解決法として,private static final なフィールドじゃなくて,private static なフィールドにして,getSinletonを以下のようにすれば良いから.
public synchronized static getSingleton(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
本当にlazy instantiation したければ private static にして getSingleton 内で初期化するだろうな.