『Effective Java』読書ノート03-プライベートコンストラクタ


一、プライベートコンストラクタとSingleton
Singleton設計モードはクラスが一度だけインスタンス化されることを確保することですが、どのようにしてクラスが一度だけインスタンス化されることを保証しますか?最善の方法は、クライアントがクラスインスタンスを自分で作成することを阻止することです.つまり、クラスインスタンスを作成するコンストラクタをプライベート化することです.これにより、クライアントがクラスインスタンスを必要とする場合、作成したインスタンスを返すことができます.これがプライベートコンストラクタとSingletonの不可解な縁である.
Singletonを作成する方法:
1、実例を公有静的メンバーとしてfinal型とする.
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { }

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

プライベートコンストラクタは一度だけ呼び出され、公有の静的finalドメインElvisをインスタンス化するために使用される.INSTANCE.
2.インスタンスをプライベート静的メンバーとして作成し、共通のメンバー静的ファクトリメソッドを提供する.
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.getInstance();
        elvis.leaveTheBuilding();
    }
}
、単一の要素のみを含む列挙タイプを記述する.
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

3つの方法を比較します.
1、公有ドメインメソッドの主な利点は、クラスメンバーを構成する宣言が、このクラスがSingletonであることを明確に示していることである.公有の静的finalドメインは、同じオブジェクトを参照することを保証する.公有ドメイン法は性能上,現代のJVM実装ではほとんど静的ファクトリ法の呼び出しをインライン化できるため,優位性はない.インラインはJVMがコンパイルしたバイナリで直接このセグメントの関数呼び出しを置き換えて、コンパイルの過程を免れて、比較的に効率的で、個人の理解、ほほほ...
2、工場方法の利点の一つは柔軟性であり、約束であるAPIを変更しない場合、この実現がSingletonを維持するかどうかを変更することができ、実現方式が多様化する.2つ目の利点は汎用性に関係しています.
3、singletonクラスのシーケンス化にかかわると、この2つの方法は列挙されていません.singletonがシーケンス化を必要とする場合、シーケンス化インタフェースを実装するだけでなく、すべてのインスタンスドメインが瞬時であることを宣言し、readResolveメソッドを提供する必要があります.そうでなければ、逆シーケンス化のたびに新しいインスタンスが生成されます.
readResolveメソッドを追加してsingletonプロパティを保証します.
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { }

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    private Object readResolve() {
        // Return the one true Elvis and let the garbage collector
        // take care of the Elvis impersonator.
        return INSTANCE;
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

ベスト・プログラミングの実践:
1、singletonがシーケンス化を必要としない場合は、3つの方式のいずれかを選択し、好みに応じて選択することができるが、最初の2つは反射によってプライベートコンストラクタを呼び出すことで2番目のインスタンスを生成することができる.
2、シーケンス化が必要な場合は、Singletonを実装するために単一要素の列挙タイプを使用することを推奨します.なぜなら、それは簡潔で、無償でシーケンス化メカニズムを提供し、複雑なシーケンス化や反射攻撃に直面したときでも、何度もインスタンス化を絶対に防止しているからです.の
二、私有構造器と実例化不可
一般的に、インスタンスは意味がないため、ツールクラスを作成するときにインスタンス化できないことを望んでいます.ディスプレイコンストラクタを提供しないと、コンパイラはデフォルトの非パラメトリックコンストラクタを作成します.これにより、お客様がツールクラスをインスタンス化することはできません.お客様がサブクラスをインスタンス化できるため、クラスを抽象クラスにすることによってクラスをインスタンス化できないように強制することはできません.このようにすると、このクラスが継承されるために使われていると誤解しやすくなります.明らかに私たちの本意に反しています.
私たちはコンストラクタを私有化することで、クラスが実例できない目的を達成することができますが、このようにすると、このクラスが布団に分類できないことになりますが、一般的なツールクラスは布団に分類する必要はありません.ほほほ、必要なら単粒にすることができます.