2

私はシングルトンの研究を行っていて、非常に基本的なシングルトン クラスを開発しました。

public class SingletonObject {
    private static SingletonObject ref;
    private SingletonObject () //private constructor
    { }

    public  static synchronized   SingletonObject getSingletonObject()
    {
        if (ref == null)
            ref = new SingletonObject();
                return ref;
        }


    public Object clone() throws CloneNotSupportedException
    {throw new CloneNotSupportedException ();
    }   
}

以下は、シングルトンをクラックした1つの方法です..

public class CrackingSingleton {

     public static void main(String[] args) throws ClassNotFoundException,
       IllegalArgumentException, SecurityException,
       InstantiationException, IllegalAccessException,
       InvocationTargetException {

        //First statement retrieves the Constructor object for private constructor of SimpleSingleton class.
        Constructor pvtConstructor = Class.forName("CrackingSingleton.SingletonObject").getDeclaredConstructors()[0];
        //Since the constructor retrieved is a private one, we need to set its accessibility to true.
        pvtConstructor.setAccessible(true);
        //Last statement invokes the private constructor and create a new instance of SimpleSingleton class.
         SingletonObject  notSingleton1 = ( SingletonObject) pvtConstructor.newInstance(null);
         System.out.println(notSingleton1.hashCode());
         System.out.println("notSingleton1 --->"+notSingleton1.toString());
         SingletonObject  notSingleton2 = ( SingletonObject) pvtConstructor.newInstance(null);
         System.out.println("notSingleton2 --->"+notSingleton2.hashCode());
         System.out.println(notSingleton2.toString());
    }
}

シングルトンをクラックできる他の方法も教えてください..!!

4

6 に答える 6

5

私が考えることができる3つの方法は次のとおりです。

シリアル化

シングルトン クラスがシリアライズ可能な場合、そのインスタンスをシリアライズし、デシリアライズして、そのクラスの 2 番目のオブジェクトを取得できます。

readResolveメソッドを実装することで、これを回避できます。

public class Singleton implements Serializable {
   private static final Singleton INSTANCE = new Singleton();

   public static Singleton getInstance(){
       return INSTANCE;
   }

   public Object readResolve() throws ObjectStreamException {
        return INSTANCE; //ensure singleton is returned upon deserialization.
   }
}

クラスローディング

同じクラスが 2 つの異なるクラス ローダーによってロードされる可能性があるため、2 つの異なるクラス ローダーによってロードされたクラスでメソッドを呼び出すだけで、シングルトン クラスの 2 つのインスタンスを作成できますgetInstance。このアプローチは、プライベート コンストラクターに違反することなく機能します。

ClassLoader cl1 = new URLClassLoader(new URL[]{"singleton.jar"}, null);
ClassLoader cl2 = new URLClassLoader(new URL[]{"singleton.jar"}, null);
Class<?> singClass1 = cl1.loadClass("hacking.Singleton");
Class<?> singClass2 = cl2.loadClass("hacking.Singleton");
//...
Method getInstance1 = singClass1.getDeclaredMethod("getInstance", ...);
Method getInstance2 = singClass2.getDeclaredMethod("getInstance", ...);
//...
Object singleton1 = getInstance1.invoke(null);
Object singleton2 = getInstance2.invoke(null);

反射

ご指摘のとおり、リフレクションを介して、クラスの 2 つのインスタンスを作成できます。前の例は、同じアプローチの変形にすぎないと思います。しかし、 を使用してこれら 2 つの発生を防止できると思いますSecurityManager

System.setSecurityManager(new SecurityManager());
于 2012-07-25T17:08:19.537 に答える
2

2 つのクラスローダーがある場合、各クラスローダーからシングルトンを作成できます。

ドキュメント「シングルトンがシングルトンではない場合」も読む価値があります。

于 2012-07-25T17:05:11.410 に答える
1

私の答えは:

なぜそれが重要なのですか?

安全でクラックできないコードを設計しようとしている場合、Singleton はそのためのソリューションではありません。通常の開発者がそのシステム インスタンスを使用するように強制するように設計されています。それを回避するこれらの方法はすべて、クラスの別のインスタンスを使用するためだけに誰かが行うことのない多くの余分な作業を必要とします。

于 2012-07-25T17:19:57.937 に答える
1

Singleton が動作しないシナリオがいくつかあります。

1.ガベージコレクションによってシングルトンクラスが破壊された場合、再度リロードされます。
2. 複数の仮想マシン内の複数
のシングルトン 3. 異なるクラス ローダーによって同時にロードされる複数のシングルトン。
4シリアライゼーションとデシリアライゼーションを経たシングルトン オブジェクトのコピー

于 2016-02-01T06:10:26.550 に答える
0

リフレクションを介して、 を設定しref = nullます。として再割り当てすることによりnull、シングルトンを遅延構築するロジックは、次の の呼び出しで再びトリガーされますgetSingletonObject

于 2012-07-25T17:03:18.043 に答える
0

バイトコード エンジニアリング ライブラリを使用して、シングルトン コンストラクターをパブリックにすることができます。

また、一部の古い Java バージョン (これは 1.3 で機能していました) では、パブリック コンストラクターとそのクラスに対するコンパイルを使用して、同じ名前のクラスを簡単に作成できます。これにより、実行時に実際のクラスのインスタンスを作成できました (この抜け穴は、後の JRE バージョンのバイトコード検証で修正されています)。

于 2012-07-25T17:08:47.693 に答える