單例模式的破壞及任何防止被破壞

2021-09-26 19:07:38 字數 2144 閱讀 1614

常用的單例模式有懶漢式、餓漢式兩種情況。實際的應用場景也是很常見,好比如資料庫連線池的設計,還有windows的task manager(任務管理器)等。

所謂單例模式就是,某乙個類只能有乙個例項,實現的核心就是將類的建構函式私有化,只能由該類建立物件,其他物件就不能呼叫該類的建構函式,即不能建立物件了。

現在看乙個問題:物件的建立方式有哪幾種? 

四種:new 、轉殖、序列化、反射。

其實上面的說法有點問題,改為:……其他物件就不能呼叫該類的建構函式,即不能通過new 來建立物件了。那麼是否還有可以通過其他的三種方式建立物件呢,即其他三種方式會不會破壞單例模式呢?

由轉殖我們可以想到原型模式,原型模式就是通過clone方法實現物件的建立的,clone方式是object方法,每個物件都有,那麼使用乙個單例模式類的物件,呼叫clone方法,再建立乙個新的物件了,那豈不是上面說的單例模式失效了。當然答案是否定,某乙個物件直接呼叫clone方法,會丟擲異常,即並不能成功轉殖乙個物件。呼叫該方法時,必須實現乙個cloneable 介面。這也就是原型模式的實現方式。還有即如果該類實現了cloneable介面,儘管建構函式是私有的,他也可以建立乙個物件。即clone方法是不會呼叫建構函式的,他是直接從記憶體中copy記憶體區域的。

解決辦法:單例模式的類不實現cloneable介面。

一是可以實現資料的持久化;二是可以物件資料的遠端傳輸。 如果過該類implements serializable,那麼就會在反序列化的過程中再創乙個物件。

/**

*  * @author 小欽

*懶漢式

*/public class singleton implements serializable

public static singleton getinstance()}}

return instance;

}}

測試類:

public class serializabledemo1 

}

//輸出的是false

序列化會通過反射呼叫無引數的構造方法建立乙個新的物件。

通過對singleton的序列化與反序列化得到的物件是乙個新的物件,這就破壞了singleton的單例性。

解決辦法:在反序列化時,指定反序化的物件例項。即只要在singleton類中定義readresolve就可以解決該問題

public class singleton implements serializable 

public static singleton getinstance()}}

return instance;

}private object readresolve()

}

主要在singleton中定義readresolve方法,並在該方法中指定要返回的物件的生成策略,就可以防止單例被破壞。

反射是可以獲取類的建構函式,再加一行 setaccessible(true);就可以呼叫私有的建構函式,建立物件了。

/**

*  * @author 小欽

*懶漢式

*/public class singleton  

public static singleton getinstance()}}

return instance;

}}

測試類:

public class testdemo 

}

//輸出:366712642

366712642

1829164700

解決辦法:當第二次呼叫建構函式時丟擲異常。

/**

*  * @author 小欽

*懶漢式

*/public class singleton  

else

}public static singleton getinstance()}}

return instance;

}

防止利用暴力反射破壞單例模式

單例模式的實現是將構造私有化,然後內部維護乙個物件,但是還是可以通過暴力反射建立多個例項,如下 我以上篇文章講的靜態內部類方式實現單例模式為例 package com.hy.practice import sun.security.jca.getinstance author hy classnam...

單例模式,解決單例破壞。

破壞單例模式的三種方法 執行緒安全情況下 單例模式有 3 個特點 單例類只有乙個例項物件 該單例物件必須由單例類自行建立 單例類對外提供乙個訪問該單例的全域性訪問點。單例模式的優點和缺點 單例模式的優點 單例模式可以保證記憶體裡只有乙個例項,減少了記憶體的開銷。可以避免對資源的多重占用。單例模式設定...

附 單例模式的破壞

序列化物件對單例模式的破壞與恢復 首先這是乙個餓漢式的單例物件構建方式,一般情況下獲取到的都是同乙個單例物件 但是當序列化寫入本地再讀入記憶體時,會重新建立乙個單例物件 為什麼會在讀入序列化後的物件時會讓單例模式失效呢?這兒從readobject 方法入手 進入這個方法後 private 進入pri...