単例類パターンの破壊防止を徹底的に理解する


優鋭授業の学習共有では,単例属性を破壊する3つの主要な方法とそれをどのように防止するかを検討した.みんなに参考にして勉強します.
必要に応じて、アプリケーションで単一の設計モードを使用することに慣れています.単一の設計モードでは、インスタンスを作成してアプリケーション全体にアクセスするしかないことはよく知られています.しかし、場合によっては、単一の動作を破壊します.3つの主な概念では,JavaにおけるSingletonクラスのsingleton属性を破ることができる.この文章では、それを破壊する方法と防止する方法について議論します.これはSingletonクラスとSingletonTestクラスの例です.单例
Singleton.Java
package demo1;
public final class Singleton {
    private static volatile Singleton instance = null;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

SingletonTest.java
 package demo1;
public class SingletonTest {
    public static void main(String[] args) {
        Singleton object1 = Singleton.getInstance();
        Singleton object2 = Singleton.getInstance();
        System.out.println("Hashcode of Object 1 - " + object1.hashCode());
        System.out.println("Hashcode of Object 2 - " + object2.hashCode());
    }
}

これは出力です.objectOneとobjectTwoと同じhashcodeを持っていることがわかります.
Hashcode of Object 1 - 1836019240
Hashcode of Object 2 - 1836019240

今、私たちはこのモードを破ります.まず、Java反射を使用します.
はんしゃ
Java Reflectionは、実行時にメソッド、クラス、インタフェースの動作をチェックまたは変更するためのAPIです.Reflection APIを使用すると、Singletonクラスに複数のオブジェクトを作成できます.次の例を考慮します:ReflectionSingleton.java
package demo1;
import java.lang.reflect.Constructor;
public class ReflectionSingleton {
    public static void main(String[] args)  {
        Singleton objOne = Singleton.getInstance();
        Singleton objTwo = null;
        try {
            Constructor constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            objTwo = (Singleton) constructor.newInstance();
        } catch (Exception ex) {
            System.out.println(ex);
        }
        System.out.println("Hashcode of Object 1 - "+objOne.hashCode());
        System.out.println("Hashcode of Object 2 - "+objTwo.hashCode());
    }
}

この例では,反射がJava反射で単一例モードを破る方法を示した.次のように2つのハッシュコードが得られます.単例モードで突破しました.
モノリシックモード反射防止
反射APIにおけるSingletonモードを防止する方法は数多くあるが、最良の解決策の1つは、インスタンスが既に存在する場合、コンストラクション関数でランタイム異常が発生することである.この場合、2番目のインスタンスを作成することはできません.
逆シーケンス化
シーケンス化では、バイトストリームのオブジェクトをファイルに保存したり、ネットワークを介して送信したりすることができます.Singletonクラスをシーケンス化してから、オブジェクトを再度逆シーケンス化すると、新しいインスタンスが作成され、逆シーケンス化はSingletonモードを破壊します.
次のコードは、逆シーケンス化によって単一の逆モードがどのように中断されるかを説明するために使用されます.SingletonクラスのSerializableインタフェースを実装します.
DeserializationSingleton.Java
package demo1;
import java.io.*;
public class DeserializationSingleton {
    public static void main(String[] args) throws Exception {
        Singleton instanceOne = Singleton.getInstance();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
        out.writeObject(instanceOne);
        out.close();
        ObjectInput in = new ObjectInputStream(new FileInputStream("file.text"));
        Singleton instanceTwo = (Singleton) in.readObject();
        in.close();
        System.out.println("hashCode of instance 1 is - " + instanceOne.hashCode());
        System.out.println("hashCode of instance 2 is - " + instanceTwo.hashCode());
    }
}

出力は次の通りです.hashcodesが2つ見えます.
hashCode of instance 1 is - 2125039532
hashCode of instance 2 is - 381259350

シングル・スキーマの逆シーケンス化の防止
この問題を克服するために,SingletonクラスのreadResolve()メソッドを上書きし,同じSingletonインスタンスを返す必要がある.Singleton.javaを更新するには、次の方法を使用します.
 protected Object readResolve() { 
           return instance; 
     }

次に、上記のDeserializationDemoクラスを実行し、出力を表示します.
hashCode of instance 1 is - 2125039532
hashCode of instance 2 is - 2125039532

クローン作成
[クローン](Clone)メソッドを使用すると、元のオブジェクトのコピーを作成できます.モノリシックモードでクローンを適用すると、これは同じことです.2つのインスタンスが作成されます.1つのインスタンスと別のインスタンスです.この場合,次のコードに示すようにSingleton原理を打ち破る.
「クローニング可能」インターフェースを実装し、上記Singletonカテゴリにcloneメソッドを上書き
Singleton.java
  @Override
    protected Object clone() throws CloneNotSupportedException  {
        return super.clone();
    }

次に、クローンをテストして、単一の例を破ります.
CloningSingleton.java

public class CloningSingleton {
    public static void main(String[] args) throws CloneNotSupportedException, Exception {
        Singleton instanceOne = Singleton.getInstance();
        Singleton instanceTwo = (Singleton) instanceOne.clone();
        System.out.println("hashCode of instance 1 - " + instanceOne.hashCode());
        System.out.println("hashCode of instance 2 - " + instanceTwo.hashCode());
    }
}

これは出力です.
hashCode of instance 1 - 1836019240
hashCode of instance 2 - 325040804

上記の出力を見ると、2つのインスタンスは異なるhashcodesを有する.これは、これらのインスタンスが異なることを意味します.
シングル・スキーマのクローン作成の防止
上のコードでは、Singletonの原理、すなわち.eは2つのインスタンスを作成した.上記の問題を克服するためには、clone()メソッドを実装/上書きし、クローンメソッドから異常CloneNotSupportedExceptionを放出する必要があります.Singletonのクローンオブジェクトを作成しようとすると、次のコードに示すように例外が放出されます.
    @Override
    protected Object clone() throws CloneNotSupportedException  {
        throw new CloneNotSupportedException();
    }

これでloningSingletonクラスを実行できます.個々のオブジェクトのクローンオブジェクトを作成すると、CloneNotSupportedExceptionが放出されます.
文章はここまで书いて、もし足りないところがあれば、补充コメントを歓迎します.この文章があなたに役に立つことを望んでいます!