怎么破坏单例模式和怎么防止单例模式被破坏
01、简介
单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点,破坏单例模式的话,就是说可以弄出两个或两个以上的实例嘛。既然可以破坏,那么我们怎么防止单例模式被破坏呢?这篇文章我会带着大家来了解一下
02、破坏单列模式的方式
- 反射
- 序列和反序列化
这里我以静态内部类单例来举例,先看下静态内部类单例的代码
1 |
|
03、反射破坏单例模式
我们来看代码
1 |
|
输出为false,说明内存地址不同,就是实例化了多次,破坏了单例模式的特性。
04、防止反射破坏单例模式
通过上面反射破坏单例模式的代码,我们可以知道,反射也是通过调用构造方法来实例化对象,那么我们可以在构造函数里面做点事情来防止反射,我们把静态内部类单例的代码改造一下,看代码
1 |
|
这样我们在通过反射创建单例对象的时候,多次创建就会抛出异常
1 |
|
05、序列化破坏单例模式
用序列化的方式,需要在静态内部类(LazyInnerClassSingleton) 实现 Serializable 接口,代码在下面的防止序列化破坏单例模式里面
这里我们先来看下序列和反序列的代码
1 |
|
结果为false,说明也破坏了单例模式
06、防止序列化破坏单例模式
这里我们先来看下改造后的代码,然后分析原理
1 |
|
在执行上面序列和反序列化代码,输出true,是不是一脸懵逼,为什么加了一个readResolve方法,就能防止序列化破坏单例模式,下面就带着大家来看下序列化的源码:
1 |
|
然后我们看下 readObject0
这个方法
1 |
|
然后我们看下readOrdinaryObject
这个方法
1 |
|
这里的关键是desc.hasReadResolveMethod()
,这段代码的意思是查看你的单例类里面有没有readResolve
方法,有的话就利用反射的方式执行这个方法,具体是desc.invokeReadResolve(obj)
这段代码,返回单例对象。这里其实是实例化了两次,只不过新创建的对象没有被返回而已。如果创建对象的动作发生频率增大,就意味着内存分配开销也就随之增大,这也算是一个缺点吧。
完整的流程就是这样,是不是很神奇。
07、总结
破坏和防止单例模式被破坏的知识点 get 到了吗,大家平时多看些源码,能了解很多有趣的东西。