前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >灭霸所有单例模式,克隆、序列化、反射机制破坏7种单例模式

灭霸所有单例模式,克隆、序列化、反射机制破坏7种单例模式

作者头像
业余草
发布2019-06-17 13:42:56
8710
发布2019-06-17 13:42:56
举报
文章被收录于专栏:业余草

单例模式实际上也不止 7 种。但是,每一种都并非安全的。今天我给大家讲一讲如何利用克隆、序列化、反射机制破坏单例模式。

我今天以痴汉式单例为例来讲,其他的单例模式破坏方式类似。

上面这个单例实现,看似很完美。但我们通过克隆、序列化、反射机制,来击破这个单例模式。

创建一个 Java 对象一般有 4 种方式:new 、克隆、序列化、反射!现在 new 这种方式不能使用了,那我们还可以使用剩下的 3 种方式!

先来看克隆!

实现 Cloneable 接口,尽管构造函数是私有,但还会创建一个对象。因为 clone 方法不会调用构造函数,会直接从内存中 copy 内存区域。所以单例模式的类是切记不要实现 Cloneable 接口。

自己运行一下,hash 值不一样,所以克隆成功了,生成了一个新对象。单例模式被成功破坏!

那么怎么抵制被克隆呢?

就是重写 clone 方法,调用 getInstance() 方法,返回已有的实例即可!

现在我们再来看序列化是如何破坏单例模式的。现在假设你的单例模式,实现了 Serializable 接口。看我下面反序列化的案例!

执行之后,hash 值不一样了,获取的对象非同一对象。结论,单例模式又被破坏了!那么怎么防止被反序列化呢?

很简单,自定义实现对象的 readResolve() 方法。

为什么实现对象的 readResolve() 方法就可以了呢?这个你可以自己 debug 一下,上面反序列化的代码。其中有一个 readOrdinaryObject 方法在做怪!

关键代码都注射的比较全,我相信你能看明白。如果还不明白,加我微信ID:xttblog。

最后,我们再来看反射是如何破坏单例模式的!

执行之后,hash 值不一样了,获取的对象非同一对象。结论,单例模式又被破坏了!那么如何解决呢?很简单,加入下面的代码。

因为执行反射会调用无参构造函数,所以上面的判断就可以起作用了!

综上所述,单例模式需要考虑,线程安全问题,效率问题,防止反射、反序列化、克隆。要不然,就有可能被黑客利用!

看到这里,有些人可能会问,这也太麻烦了,有没有更简便的方法呢?有,枚举模式。枚举类型是绝对单例的,可以无责任使用。

一个枚举,就算实现双接口,也是无论如何都无法被破坏的。枚举无法克隆,没有这样的方法。没有构造函数,会抛出异常。就算你在枚举里加了构造函数,也是一样的。对于反序列化 Java 仅仅是将枚举对象的 name 属性输出到结果中,反序列化的时候则是通过 java.lang.Enum 的 valueOf 方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了 writeObject、readObject、readObjectNoData、writeReplace 和 readResolve 等方法。所以,枚举才是实现单例模式的最好方式!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年06月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档