日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深度解析单例与序列化之间的爱恨情仇

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度解析单例与序列化之间的爱恨情仇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自?深度解析單例與序列化之間的愛恨情仇

本文將通過實例+閱讀Java源碼的方式介紹序列化是如何破壞單例模式的,以及如何避免序列化對單例的破壞。

單例模式,是設計模式中最簡單的一種。通過單例模式可以保證系統中一個類只有一個實例而且該實例易于外界訪問,從而方便對實例個數的控制并節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。關于單例模式的使用方式,可以閱讀單例模式的七種寫法

但是,單例模式真的能夠實現實例的唯一性嗎?

答案是否定的,很多人都知道使用反射可以破壞單例模式,除了反射以外,使用序列化與反序列化也同樣會破壞單例。

序列化對單例的破壞 首先來寫一個單例的類: code 1

接下來是一個測試類:
code 2

輸出結構為false,說明:

通過對Singleton的序列化與反序列化得到的對象是一個新的對象,這就破壞了Singleton的單例性。

這里,在介紹如何解決這個問題之前,我們先來深入分析一下,為什么會這樣?在反序列化的過程中到底發生了什么。

ObjectInputStream

對象的序列化過程通過ObjectOutputStream和ObjectInputputStream來實現的,那么帶著剛剛的問題,分析一下ObjectInputputStream 的readObject?方法執行情況到底是怎樣的。

為了節省篇幅,這里給出ObjectInputStream的readObject的調用棧:

這里看一下重點代碼,readOrdinaryObject方法的代碼片段:

code 3

上面主要貼出兩部分代碼。先分析第一部分:

code 3.1

這里創建的這個obj對象,就是本方法要返回的對象,也可以暫時理解為是ObjectInputStream的readObject返回的對象。其生成方式如下:

isInstantiable:如果一個serializable/externalizable的類可以在運行時被實例化,那么該方法就返回true。針對serializable和externalizable我會在其他文章中介紹。

desc.newInstance:該方法通過反射的方式調用無參構造方法新建一個對象。

所以。到目前為止,也就可以解釋,為什么序列化可以破壞單例了?

答:序列化會通過反射調用無參數的構造方法創建一個新的對象。


那么,接下來我們再看剛開始留下的問題,如何防止序列化/反序列化破壞單例模式。

防止序列化破壞單例模式

先給出解決方案,然后再具體分析原理:只要在Singleton類中定義readResolve就可以解決該問題。單例的類代碼如下:

code 4

繼續運行以下測試類:

本次輸出結果為true,現在我們的單例就沒有被破壞。具體原理,我們回過頭繼續分析code 3中的第二段代碼:

code 3.2


hasReadResolveMethod:如果實現了serializable 或者 externalizable接口的類中包含readResolve則返回true

invokeReadResolve:通過反射的方式調用要被反序列化的類的readResolve方法。

所以,原理也就清楚了,主要在Singleton中定義readResolve方法,并在該方法中指定要返回的對象的生成策略,就可以防止單例被破壞。


總結

以上是生活随笔為你收集整理的深度解析单例与序列化之间的爱恨情仇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。