单例模式是否安全
在设计模式-单例模式这篇博客介绍了单例模式的几种实现方式,但是按照上述方式是否能够保证一定是单例呢?答案是否定的,如果不加限制,通过反射和序列化可以破坏单例模式。
破坏单例模式
反射
单例模式把类的构造方法设置为private访问级别,导致外部类无法新建对象,通过反射我们可以修改访问级别,从外部新建单例类对象。以饿汉模式为例
1 | public class StarveSingleton { |
从结果来看,通过反射的方式,单例模式被破坏,我们可以随意产生新的单例类实例。
序列化
如果单例类继承了serializable接口,那么序列化也可以破坏单例模式。依然以饿汉模式为例
1 |
|
可以看出序列化可以破坏单例模式。
如何防止单例模式被破坏
反射
可以在构造函数里配置一个标志位,当构造函数被第二次调用时报错
1 |
|
这样就解决了反射破坏单例的问题。
序列化
对于序列化来说,需要实现readSolve()方法来保证每次返回的都是一个实例
1 |
|
readResolve方法是ObjectInputStream类进行反序列化的一个特殊机制,这里后续再展开,总之这里实现该方法可以保证单例不被破坏。
总结
下面是我对这个知识点的心得。如何破坏单例模式,这道题怎么思考呢?单例模式和创建对象相关,我们知道创建对象有4种方式
- 直接new
- 调用clone方法
- 序列化反序列化
- 反射
其中方式1已经被单例模式限制住,方式2我们一般很少实现clone接口,所以可以破坏单例模式的方法就从3,4而来。