前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >单例与序列化的那些事儿

单例与序列化的那些事儿

作者头像
哲洛不闹
发布2018-09-18 14:23:15
6170
发布2018-09-18 14:23:15
举报
文章被收录于专栏:java一日一条java一日一条

本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏。

单例模式,是设计模式中最简单的一种。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

但是,单例模式真的能够实现实例的唯一性吗?

答案是否定的,很多人都知道使用反射可以破坏单例模式,除了反射以外,使用序列化与反序列化也同样会破坏单例。

序列化对单例的破坏

首先来写一个单例的类:

code 1

接下来是一个测试类:

code 2

输出结构为false,说明:

通过对Singleton的序列化与反序列化得到的对象是一个新的对象,这就破坏了Singleton的单例性。

这里,在介绍如何解决这个问题之前,我们先来深入分析一下,为什么会这样?在反序列化的过程中到底发生了什么。

ObjectInputStream

对象的序列化过程通过ObjectOutputStream和ObjectInputputStream来实现的,那么带着刚刚的问题,分析一下ObjectInputputStream 的readObject 方法执行情况到底是怎样的。

为了节省篇幅,这里给出ObjectInputStream的readObject的调用栈:

readObject--->readObject0--->readOrdinaryObject--->checkResolve

这里看一下重点代码,readOrdinaryObject方法的代码片段: code 3

code 3 中主要贴出两部分代码。先分析第一部分:

code 3.1

这里创建的这个obj对象,就是本方法要返回的对象,也可以暂时理解为是ObjectInputStream的readObject返回的对象。

isInstantiable:如果一个serializable/externalizable的类可以在运行时被实例化,那么该方法就返回true。针对serializable和externalizable我会在其他文章中介绍。 desc.newInstance:该方法通过反射的方式调用无参构造方法新建一个对象。

所以。到目前为止,也就可以解释,为什么序列化可以破坏单例了?

答:序列化会通过反射调用无参数的构造方法创建一个新的对象。

那么,接下来我们再看刚开始留下的问题,如何防止序列化/反序列化破坏单例模式。

防止序列化破坏单例模式

先给出解决方案,然后再具体分析原理:

只要在Singleton类中定义readResolve就可以解决该问题:

code 4

具体原理,我们回过头继续分析code 3中的第二段代码:

code 3.2

hasReadResolveMethod:如果实现了serializable 或者 externalizable接口的类中包含readResolve则返回true

invokeReadResolve:通过反射的方式调用要被反序列化的类的readResolve方法。

所以,原理也就清楚了,主要在Singleton中定义readResolve方法,并在该方法中指定要返回的对象的生成策略,就可以方式单例被破坏。

总结

在涉及到序列化的场景时,要格外注意他对单例的破坏。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java一日一条 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 序列化对单例的破坏
  • ObjectInputStream
  • 防止序列化破坏单例模式
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档