溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

徹底搞懂防止破壞單例類模式

發布時間:2020-07-14 17:03:48 來源:網絡 閱讀:152 作者:wx5deb0084464f6 欄目:編程語言

在優銳課的學習分享中,我們探討了破壞單例屬性的三種主要方法以及如何防止它。分享給大家參考學習。

我們習慣于在需要時在我們的應用程序中使用單例設計模式。 眾所周知,在單例設計模式中,我們只能創建一個實例并在整個應用程序中訪問它。 但是在某些情況下,它將破壞單例行為。
在三個主要概念中,我們可以打破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反射來打破單例模式。 你將獲得兩個哈希碼,如下所示。 它在單例模式上有所突破。

防止單例模式反射

有很多方法可以防止反射API中的Singleton模式,但是最好的解決方案之一是,如果實例已經存在,則在構造函數中引發運行時異常。 在這種情況下,我們無法創建第二個實例。

反序列化

在序列化中,我們可以將字節流的對象保存到文件中或通過網絡發送。 假設你先序列化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.

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

克隆

使用“克隆”方法,我們可以創建原始對象的副本; 如果我們在單例模式中應用克隆,這是同一回事。 它將創建兩個實例:一個實例和另一個實例。 在這種情況下,我們將打破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

如果我們看到上面的輸出,則兩個實例具有不同的hashcodes。 這意味著這些實例不相同。

防止單例模式克隆

在上面的代碼中,它打破了Singleton原理,即。 e創建了兩個實例。 為了克服上述問題,我們需要實現/覆蓋clone()方法并從克隆方法中拋出異常CloneNotSupportedException。 如果有人嘗試創建Singleton的克隆對象,它將拋出異常,如以下代碼所示。

    @Override
    protected Object clone() throws CloneNotSupportedException  {
        throw new CloneNotSupportedException();
    }

現在,我們可以運行loningSingleton類; 在創建單個對象的克隆對象時,它將拋出CloneNotSupportedException。

文章寫到這里,如有不足之處,歡迎補充評論.希望這篇文章對你有用!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女