at backyard

Color my life with the chaos of trouble.

Javaでシングルトンパターン、static変数が生成されるタイミング

Javaでシングルトンパターン

Javaでシングルトンパターンのおさらいをした。
これはJava Gold試験の出題範囲でもある。


まずはシングルトンパターン自体のおさらい。
Wikipediaより引用。

GoF(Gang of Four; 4人のギャングたち)によって定義された。 Singleton パターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される。

一つしか存在しないはずのロケールなどが複数作られてしまわないように、ということですな。
シングルトンパターンのクラスを2つ書き出してみる。

// Singleton pattern 1
class Singleton_01{
	private static Singleton_01 instance;
	private Singleton_01(){}
	
	public static synchronized Singleton_01 getInstance(){
		if(instance == null){ // 既にインスタンスが生成されていた場合、新たに生成は行われない
			instance = new Singleton_01();
		}
		return instance;
	}
}


このようなクラスの場合、インスタンスが生成されるタイミングは、一回目にgetInstanceメソッドが呼ばれた時のみ。
あとはgetInstanceメソッドが呼ばれてもインスタンスの生成は行われない。
つまり、インスタンスは一つしか存在されないことが保証される。

// Singleton pattern 2
class Singleton_02{
	private static Singleton_02 instance = new Singleton_02();
	private Singleton_02(){}
	public static Singleton_02 getInstacne(){
		return instance;
	}
	
}

このパターンでも、instance変数に入るインスタンスは一つのみとなるので、
何度呼び出しても、同じインスタンスが返ってくることが保証される。
、、、というのは分かったけど、static変数にインスタンスが代入されるタイミングはどこになるのだろうか?

変数にインスタンスが参照されるタイミング

というわけで、Singleton pattern 2を少しだけ改造してみた。
これでstatic変数が宣言されたタイミングで"Call a constructor"と呼ばれる

// Singleton pattern 2
class Singleton_02{
	private static Singleton_02 instance = new Singleton_02();
	private Singleton_02(){
		System.out.println("Call a constructor");
	}
	public static Singleton_02 getInstacne(){
		return instance;
	}
	
}

検証用に実行クラスを作成する。

public class Test {
	public static void main(String[] args){
		System.out.println("TEST start");
		Singleton_02 s1 = Singleton_02.getInstacne();
		System.out.println("s1 : " + s1);
		Singleton_02 s2 = Singleton_02.getInstacne();
		System.out.println("s2 : " + s2);
		Singleton_02 s3 = Singleton_02.getInstacne();
		System.out.println("s3 : " + s3);
	}
}

実行結果は下記の通り。

TEST start
Call a constructor
s1 : test.Singleton_02@7852e922
s2 : test.Singleton_02@7852e922
s3 : test.Singleton_02@7852e922

Singleton_02のgetInstacneメソッドが呼ばれたタイミングで、
最初に一度だけstatic変数にインスタンスが代入されているようだ。