常用的單例模式有懶漢式、餓漢式兩種情況。實際的應用場景也是很常見,好比如資料庫連線池的設計,還有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...