トップ 一覧 Farm 検索 ヘルプ RSS ログイン

Java/シングルトン同士で呼びあう場合の挙動の変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
{{category プログラミング}}
{{category JAVA}}
{{category 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になっているといいうことだろうか。