单例模式谁都会,破坏单例模式听说过吗?
美团到店的原题,手写一个单例模式然后问如何破坏这个单例模式?
单例模式谁都会,懒汉、饿汉、双重校验锁、匿名内部类、Enum,倒背如流了都,那如何破坏单例呢?
以最简单的饿汉式写法为例:
所谓单例,就是保证一个类只有一个实例对象,那想要破坏单例模式,无非就是创建多个实例对象罢了
那单例模式的构造函数都是private的,我们没法直接通过new来构造对象,也就是说通过new这种方式去破坏单例的可能性是不存在的,得另寻他路。
除了new,创建对象的方式还有clone,反序列化,以及反射。
要调用clone方法,那么必须实现Cloneable接口,但是单例模式是不能实现这个接口的,因此排除这种可能性。所以我们要讨论的其实就是如何通过反序列化和反射对单例模式进行破坏反序列化破坏单例
序列化是破坏单例模式的一大利器。相比于克隆,实现序列化在实际操作中更加不可避免,有些类,它就是一定要序列化。
下面我们来做个测试,在上面的单例模式中实现序列化接口,然后先通过getInstance拿到一个对象,对这个对象进行序列化再反序列化拿到一个对象,比较两个对象是否是同一个对象:
结果为false,说明通过对Singleton的序列化再反序列化得到的对象是一个新的对象,这就破坏了Singleton的单例性。
反序列化是怎么创建一个新对象的?
我们可以点击readObject这个方法看看
核心是readObject0,继续点进去:
根据传入参数类型的不同,调用了不同的方法进行反序列化,点进针对Object的readOrdinaryObject方法看看:
真相大白了,反序列化底层其实就是使用了反射帮我们创建了一个新的对象。如何阻止反序列化破坏单例?
现在我们在Singleton类中实现一个readResolve方法,该方法直接返回了这个单例对象:
重新执行下,发现结果为true!也就是说instance1和instance2是同一个对象!
具体是什么原理,我们来看看刚才的readOrdinaryObject方法:
可以看到,在条件判断中desc。hasReadResolveMethod()会判断类是否有readResolve()方法,如果有的话会通过desc。invokeReadResolve(obj)去反射调用该方法,由于我们的readResolve方法直接返回了instance,不会创建一个新对象,这样最终就保证了类实例对象的唯一性
所以,如果想要防止单例被反序列化破坏,就让单例类实现readResolve()方法反射破坏单例
上面说到,反序列化底层其实就是通过反射来创建一个新对象的,我们直接来看反射是怎么破坏单例的:
执行结果当然是false了如何阻止反射破坏单例?
反射是怎么创建新对象的?是通过类的构造函数来的
所以如果我们想要阻止反射破坏单例,我们就需要修改类的构造函数:
重新执行一遍我们的代码,不出所料抛异常了,这样便防止了单例被反射破坏:
不过这种构造函数判断的方法,只能阻止饿汉式的单例模式,没法阻止懒汉式的单例!
我们可以来写个懒汉模式测试下:
执行下,发现结果仍然是抛异常:
什么情况?
别急,我们把instance1和instance2的构建顺序调换下:
再执行,结果就是false了!!!
这是因为懒汉式的对象只有调用的时候才被创建,我们先调用反射通过私有构造函数来创建对象,这样就越过了instance!null的判断,不会抛异常,再通过getInstance创建对象,这两个对象就不是同一个对象了,即单例模式被破坏了。
总结下,如果今后需要自己手动实现一个单例的话,可以选择【构造函数判断】【实现readResolve()方法】的方式来防止单例被破坏优雅的单例实现:Enum
那如果我不想在构造函数里面做判断,也不想写readResolve()方法,我就想安安静静写个单例,有没有更简单更优雅的方法?
答案是有的!可以选择使用Enum枚举来实现单例模式
用反射来测试下,结果是直接抛异常了java。lang。NoSuchMethodException
简单来说就是因为singletonClass。getDeclaredConstructor()没有找到Singleton的无参构造器,这是为啥?
主要是因为,一旦一个类声明为枚举,实际上就是继承了java。lang。Enum,来看看Enum类源码:
Enum有两个参数name和ordial两个属性,我们自己写的单例类继承了父类Enum的构造函数,所以在上述的getDecalredConstructor才会找不到无参构造器,那么是不是我们去调用父类的构造器就可以了呢?我们来测试一下:
哦吼,运行后直接抛IllegalArgumentException异常了
无法通过反射创建Enum对象!!!我们点进去报错的22行即constructor。newInstance一探究竟:
简单来说就是反射在通过newInstance创建对象时,会检查该类是否被ENUM修饰,如果是则直接抛出异常,反射失败,所以枚举是不怕反射暴力破解构造器的
上面说枚举是可以阻止反射通过暴力破解构造函数来破坏单例的,再来看枚举是如何阻止反序列化破坏单例的。
事实上,枚举对象的序列化、反序列化有自己的一套机制:序列化的时候,仅仅是将枚举对象的name属性输出到结果中反序列化的时候则是通过java。lang。Enum的valueOf方法来根据name查找枚举对象
来看看Enum。valueOf方法:
继续看getEnumConstantsShared()源码:
水落石出啦,仍然是通过反射做的,先获取枚举类的values()方法,再得到所有枚举对象。
简单总结下:每个枚举对象都有一个唯一的name属性序列化只是将name属性序列化在反序列化的时候,通过一个Map(key,value)存储name和与之对应的对象之间的映射,然后通过name就可以直接获得原来的Enum对象,而不会创建一个新对象!也就是说反序列化Enum类对象拿到的仍然是原来的对象,这样就使得Enum类型实现了单例模式下的序列化安全
来源:https:mp。weixin。qq。comsYFw0QitVvn4z7DhZiT4tA
摩根大通2023年中国经济将增长5。6,房价下半年有望回升2023年中国实际消费增速大概为78。消费有望成为今年中国经济疫后复苏最主要的动力图IC文《财经》记者邹碧颖编辑王延春防疫政策优化调整三个月以来,市场对……
母爱毋伤即使犯了错误你依然值得被爱中国小康网独家专稿文张楠即使犯了错误,你依然值得被爱在漫长的复杂的情感关系中,母女关系被推到了风口浪尖。或许你看到了一个困惑的自己,对自己与妈妈的关系感觉不对……
1官网配置APNAPNSSL证书使用SSL加密来保护通信,并可以确保通知仅来自受信任的源。第一步:创建MACOS应用程序,获取BundleID注意:BundleID需要与iOS端应用程序……
国产武侠哪家强?steam武侠风国产独立游戏推荐武侠是国人难以割舍的情怀,从另类的角度解读上来看,武其实代表着自身,侠代表着众生百态与自身的联系。每当在生活中面临重大选择之时,侠之一字就会时刻提醒我们要乐于助人。喜欢武侠的游……
厚纪资本贾凤贺硬科技投资红海中,投研要做到足够深度化差异化厚纪资本合伙人贾凤贺介绍说,我们已经退出项目的平均IRR超过20,整体投资的成功率超过90。目前,厚纪资本累计管理资产规模超40亿元,退出项目资金超36亿元,现金退出项目加上可……
三款热门3A新作将上线游戏本性能亟待升级,天选4系列了解一下虽然现如今手游拥有非常高的热度,但对于游戏发烧友而言,端游始终才是yyds,毕竟许多的3A大作,无论是在玩法体验还是画质呈现上,都是手游所无法企及的。像是近期,包括《狂野之心》……
在圆寂之前,万灯庵的住持,终于体悟到了禅理的机要师父对她说:点一盏灯,使它不但能照亮你,而且不会留下你的身影,就可以体悟了!但是,令她困惑的是,一片灯海将自己团团围住,还是会见到自己的影子。一个人有多大的灵性,就在于他……
两味中药,摆脱乳腺结节囊肿!乳腺结节问题,越来越普遍,很多女性朋友,都在为此而困扰。今天给诸位说两味,被我们低估了的中药,对乳腺囊肿、乳腺结节、乳腺炎等,效果出乎意料!组成:石见穿、紫花地丁……
兔元素年俗好物受宠看年货购物车都有些啥?随着兔元素年俗好物一起装进购物车的还有家宴预制菜;身着汉服去拜年,新年穿搭年味儿满满。今年过年除了回老家,还要出去浪没想到,00后、80后才是恋家的那一批人,70后更愿意……
沉浸于音乐的美质与内涵,SP100M让你的愿望实现德生SP100M平衡王,低频饱满,声音宽松,具有很强的音乐情感表达力德生成立于1994年,是全球最大的收音机品牌。2015年起,德生锐意进军HIFI界,推出全系列发烧音响……
科技考古方兴未艾助力中国考古进入黄金时代央视网消息:从传统的手铲释天书,到各种黑科技大显身手,在刚刚过去的一年,科技成为考古发展的新动力。2022年,河南二里头、四川三星堆,漳州圣杯屿水下考古,这些考古重大项目不断取……
电商企业要如何抓住流量,实现高转化?复盘每年的双11,对于电商人来说,只有做好万全的准备,才能在这个电商狂欢节里抓取更多的流量,实现高转化。而客服则是提高转化率的突破口。大促期间在平台的流量加持下,成千上万的客户……
桶装水20天了还能饮用吗?桶装水是生活中比较常见的一种饮用水,它喝起来比较方便,很多人喝桶装水。桶装水打开之后要尽快喝完,如果桶装水放了20天就不建议喝了,即使烧开了也不适合喝了。桶装水20天了还……
2022年倒计时不懊恼,不将就,不执着冬日生活打卡季这一年你过得好么?每个人都有自己的答案,其中的酸甜苦辣只有自己知道,你无法希求别人对你感同身受,毕竟大家都有各自的难言之隐。看开就好,一个人成熟的标志,就是……
武汉三镇队足协杯四分之一决赛为何不敢正面对抗山东泰山队从整个中超联赛冠军归属以武汉三镇队平分净胜球的微弱优势夺冠,本身就有些含糊不清,足协又在末轮宣布北京国安、天津队弃权的情况下原因复杂:1、三镇队外援与主教练佩德罗团队放假……
苹果明年iOS将向第三方应用商店开放每日分享最新,最流行的软件开发知识与最新行业趋势,希望大家能够一键三连,多多支持,跪求关注,点赞,留言。Apple计划对iOS和其他产品和服务进行大规模更改,以满足《数字……
老牌厂商重现巅峰,骁龙888P曲面屏68W快充,12512G冬日生活打卡季随着智能手机的发展,如今很多厂商都出局了,以往我们熟悉的很多品牌,比如诺基亚,LG,HTC,黑莓等等,现如今已经不见踪影,但其中也有几家苟延残喘的,像是魅族……
何惧张本美和,国乒再出天才少女,连胜日本夺双冠,被称小张怡宁目前,国乒主力选手都在参加国内的乒超联赛。不过,在日本,也有一项传统赛事正在进行中,这项赛事被称为乒坛未来之星的摇篮,这项赛事便是乒乓球东亚希望杯。而在这届东亚希望杯上,国乒女……
自驾旅行之前,一定要做的那些准备,你都做了吗?时下,自驾旅行已经成为了越来越多人青睐的旅行方式。我也最爱自驾游,一来可以一路欣赏沿路风光,二来目的地的选择也更灵活,也能节省不少时间。不过,在自驾出行之前,我们也……
央行年内第二次降准落地新增5000亿元支持实体经济昨天(5日),中国人民银行正式降低金融机构存款准备金率0。25个百分点,这是今年内央行第二次降准。这次降准共计释放长期资金约5000亿元。下调后,金融机构加权平均存款准备……
英法狭路相逢,谁能赢得8强战?北京时间5日,卡塔尔世界杯16强,法国、英格兰兵不血刃战胜各自对手挺进8强。双方将在北京时间11日凌晨3时展开角逐,争夺一个半决赛席位。前四场比赛,两支球队都展现出了不俗……
华为P50怎么了?8256G突然降1800块,鸿蒙旗舰放低了很多人在纠结华为P50系列和华为Mate50系列两者该怎么选?其实这个问题很简单,对于预算充足的朋友,直接对华为Mate50系列下手,但如果讲究性价比的话,果断考虑华为P50系……
善待自己一则噩耗,让我忙碌的的脚步突然停了下来。我的邻居走了,时间将他的生命定格在了40岁,留下了年迈的父母,妻子还有一对未成年的儿女。记得小时候我们总在块一玩,一起放羊,给羊割草,在……
我们带着ChatGPT来啦大家应该都知道了,12月1日OpenAI发布了全新的大语言模型ChatGPT,令人惊艳的性能火爆了整个AIGC圈子。据说ChatGPT是GPT3的衍生产品,通过对各种领域……