引言
單例模式作為設計模式中的基石,廣泛應用于配置管理、線程池、緩存系統等關鍵場景。然而,許多開發者誤以為“私有構造函數”足以保障其唯一性,卻忽視了反射機制、對象克隆、序列化反序列化這三把“隱形利刃”——它們能繞過常規防御,悄無聲息地創建多個實例,引發數據污染、資源競爭等災難性后果。
單例模式的破壞
反射
反射可以訪問和修改類的私有構造函數,從而創建新的實例,破壞單例約束。
解決辦法:
- 構造方法內判斷已經實例化過了,如果已經實例化過了,第二次實例化的時候,拋出異常。
- 使用枚舉創建單例對象。
private Singleton() {if (SingletonHolder.INSTANCE != null) {throw new RuntimeException("不允許通過反射創建實例");}
}
克隆
如果單例類實現了Cloneable
接口,并且沒有覆蓋clone
方法,則可以通過克隆創建多個實例。
解決辦法:
- 重寫clone()方法,調clone()時直接返回已經實例的對象。
- 使用枚舉創建單例對象。
序列化
序列化和反序列化可以創建單例類的新實例,破壞單例約束。java.io.ObjectInputStream 在反序列化過程中調用的。如果一個類實現了 Serializable 接口,并提供了 readResolve 方法,那么在該類的實例被反序列化時,readResolve 方法會被調用,以提供最終返回的對象。
解決辦法:
- 在反序列化時的回調方法 readResolve()中返回單例對象。
- 使用枚舉創建單例對象。
感謝您的閱讀!如果文章中有任何問題或不足之處,歡迎及時指出,您的反饋將幫助我不斷改進與完善。期待與您共同探討技術,共同進步!