サーチ…


前書き

シングルトンは、1つのインスタンスのみを持つクラスです。シングルトンデザインパターンの詳細については、「 デザインパターン」タグの「 シングルトン」トピックを参照してください。

列挙型シングルトン

Java SE 5
public enum Singleton {
    INSTANCE;

    public void execute (String arg) {
        // Perform operation here 
    }
}

列挙型はプライベートコンストラクタを持ち、最終的なものであり、適切なシリアル化機構を提供します。それらは非常に簡潔であり、スレッドセーフな方法で遅延的に初期化されます。

JVMは、列挙型の値がそれぞれ複数回インスタンス化されないことを保証します。これにより、列挙型のシングルトンパターンは反射攻撃に対して非常に強力な防御を提供します。

enumパターン保護しないものは、物理的にソースコードに要素を追加している他の開発者です。そのため、シングルトンにこの実装スタイルを選択した場合、これらの列挙型に新しい値を追加しないことを明確に文書化することが不可欠です。

これは、Joshua BlochがEffective Javaで説明したように、シングルトンパターンを実装するための推奨される方法です。

ダブルチェックロック付きスレッドセーフシングルトン

このタイプのシングルトンはスレッドセーフであり、シングルトンインスタンスが作成された後の不要なロックを防ぎます。

Java SE 5
public class MySingleton {

    // instance of class
    private static volatile MySingleton instance = null;

    // Private constructor
    private MySingleton() {
        // Some code for constructing object
    }

    public static MySingleton getInstance() {
        MySingleton result = instance;
        
        //If the instance already exists, no locking is necessary
        if(result == null) {
            //The singleton instance doesn't exist, lock and check again
            synchronized(MySingleton.class) {
                result = instance;
                if(result == null) {
                    instance = result = new MySingleton();
                }
            }
        }
        return result;
    }
}

強調しなければならないのは、Java SE 5より前のバージョンでは、上記の実装が正しくないため、避けるべきです。 Java 5より前のJavaでは、ダブルチェックロックを正しく実装することはできません。

列挙型を使用しないシングルトン(熱心な初期化)

public class Singleton {    

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

この例は事実上遅延初期化であると主張できます。 Java言語仕様の第12.4.1項は次のように述べています。

クラスまたはインタフェースタイプTは、次のいずれかが最初に現れる直前に初期化されます。

  • Tはクラスであり、Tのインスタンスが作成される
  • Tはクラスであり、Tによって宣言された静的メソッドが呼び出される
  • Tで宣言された静的フィールドが割り当てられます。
  • Tで宣言された静的フィールドが使用され、フィールドは定数変数ではありません
  • Tは最上位クラスであり、T内に字句的にネストされたアサーション文が実行される。

したがって、クラスに他の静的フィールドや静的メソッドがない限り、初めてgetInstance()メソッドが呼び出されるまで、 Singletonインスタンスは初期化されません。

ホルダークラスを使用したスレッドセーフな遅延初期化| Bill Pughシングルトンの実装

public class Singleton {
    private static class InstanceHolder {
        static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private Singleton() {}
}

これにより、 Singleton.getInstance()への最初の呼び出しでINSTANCE変数が初期化され、追加の同期化を必要とせずに静的初期化に対する言語のスレッド安全性が保証されます。

この実装はBill Pughシングルトンパターンとも呼ばれます。 [ウィキ]

シングルトンの拡張(シングルトン継承)

この例では、基本クラスのSingleton"Hello world!"を返すgetMessage()メソッドを提供しています"Hello world!"メッセージ。

サブクラスUppercaseSingletonLowercaseSingletonは、メッセージの適切な表現を提供するgetMessage()メソッドをオーバーライドします。

//Yeah, we'll need reflection to pull this off.
import java.lang.reflect.*;

/*
Enumeration that represents possible classes of singleton instance.
If unknown, we'll go with base class - Singleton.
*/
enum SingletonKind {
    UNKNOWN,
    LOWERCASE,
    UPPERCASE
}

//Base class
class Singleton{

    /*
    Extended classes has to be private inner classes, to prevent extending them in 
    uncontrolled manner.
     */
    private class UppercaseSingleton extends Singleton {

        private UppercaseSingleton(){
            super();
        }

        @Override
        public String getMessage() {
            return super.getMessage().toUpperCase();
        }
    }

    //Another extended class.
    private class LowercaseSingleton extends Singleton
    {
        private LowercaseSingleton(){
            super();
        }

        @Override
        public String getMessage() {
            return super.getMessage().toLowerCase();
        }
    }

    //Applying Singleton pattern
    private static SingletonKind kind = SingletonKind.UNKNOWN;

    private static Singleton instance;

    /*
    By using this method prior to getInstance() method, you effectively change the
    type of singleton instance to be created.
     */
    public static void setKind(SingletonKind kind) {
        Singleton.kind = kind;
    }

    /*
    If needed, getInstance() creates instance appropriate class, based on value of
    singletonKind field.
     */
    public static Singleton getInstance() 
        throws  NoSuchMethodException, 
                IllegalAccessException, 
                InvocationTargetException, 
                InstantiationException {

        if(instance==null){
            synchronized (Singleton.class){
                if(instance==null){
                    Singleton singleton = new Singleton();
                    switch (kind){
                        case UNKNOWN:

                            instance = singleton;
                            break;

                        case LOWERCASE:

                            /*
                             I can't use simple

                             instance = new LowercaseSingleton();

                             because java compiler won't allow me to use
                             constructor of inner class in static context,
                             so I use reflection API instead.

                             To be able to access inner class by reflection API,
                             I have to create instance of outer class first.
                             Therefore, in this implementation, Singleton cannot be
                             abstract class.
                             */

                            //Get the constructor of inner class.
                            Constructor<LowercaseSingleton> lcConstructor =
                                    LowercaseSingleton.class.getDeclaredConstructor(Singleton.class);

                            //The constructor is private, so I have to make it accessible.
                            lcConstructor.setAccessible(true);

                            // Use the constructor to create instance.
                            instance = lcConstructor.newInstance(singleton);

                            break;

                        case UPPERCASE:

                            //Same goes here, just with different type
                            Constructor<UppercaseSingleton> ucConstructor =
                                    UppercaseSingleton.class.getDeclaredConstructor(Singleton.class);
                            ucConstructor.setAccessible(true);
                            instance = ucConstructor.newInstance(singleton);
                    }
                }
            }
        }
        return instance;
    }

    //Singletons state that is to be used by subclasses
    protected String message;

    //Private constructor prevents external instantiation.
    private Singleton()
    {
        message = "Hello world!";
    }

    //Singleton's API. Implementation can be overwritten by subclasses.
    public String getMessage() {
        return message;
    }
}

//Just a small test program
public class ExtendingSingletonExample {

    public static void main(String args[]){

        //just uncomment one of following lines to change singleton class

        //Singleton.setKind(SingletonKind.UPPERCASE);
        //Singleton.setKind(SingletonKind.LOWERCASE);

        Singleton singleton = null;
        try {
            singleton = Singleton.getInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        System.out.println(singleton.getMessage());
    }
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow