Java/シングルトン同士で呼びあう場合の挙動
次のような二つのクラスを考える。これらのクラスでは、それぞれのコンストラクタで互いのインスタンスを取得しようとしている。
public class A{ private static A instance = new A(); public String mesg = "initial"; public static A getInstance(){ return instance; } private A(){ System.out.println("A is instanciated."); B b = B.getInstance(); mesg = "change"; } public static void main(String args[]){ A a = A.getInstance(); } }
public class B{ private static B instance = new B(); public static B getInstance(){ return instance; } private B(){ System.out.println("B is instanciated."); A a = A.getInstance(); System.out.println(a.mesg); } }
これをコンパイルして実行すると、
miyo@penne:% java A A is instanciated. B is instanciated.
となった後、処理が止まってしまう。
環境は、FreeBSD 5.3-RELEASE上のlinux_base-8-8.0_6によるlinuxエミュレータ上のJava 1.4.2_06である。
Javaでは
newの段階(瞬間?)で、コンストラクタのすべての処理が終了している保証はない
と人から聞いていたので、
逆にこのようなコードの場合、Bでは、a.mesgで"initial"が取得できてしまうのかなぁと思っていたのだけど...
さらに、MacやWindowsでも実験をしてみたところ、
C:?Documents and Settings?miyo>java -cp v:? A A is instanciated. B is instanciated. Exception in thread "main" java.lang.ExceptionInInitializerError at A.<init>(A.java:13) at A.<clinit>(A.java:3) Caused by: java.lang.NullPointerException at B.<init>(B.java:12) at B.<clinit>(B.java:3) ... 2 more
となって、例外を出力した。
コンストラクタがきちんと終了するまではインスタンスがきちんとnullになっているといいうことだろうか。