Effective Java(3rd)-Item89 對于實例的控制,寧可使用枚舉類型也不愿使用readResolve

??項目3描述了單例模式,并給出了下面的單例類示例。該類限制對其構造函數的訪問,以確保只創建一個實例:


image.png

??如第3項所述,如果將單詞implementation Serializable添加到該類的聲明中,該類將不再是單例的。類使用默認序列化表單還是自定義序列化表單并不重要 類是否提供顯式的readObject方法并不重要( item88)。任何readObject方法,不管是顯式的還是默認的,都會返回一個新創建的實例,這個實例與類初始化時創建的實例不同。

??readResolve特性允許您用另一個實例替換readObject [Serialization, 3.7]創建的實例。如果正在反序列化的對象的類使用正確的聲明定義了readResolve方法,則在新創建的對象反序列化之后,將在該對象上調用該方法。該方法返回的對象引用將代替新創建的對象返回。在該特性的大多數使用中,不保留對新創建對象的引用,因此它立即就有資格進行垃圾收集。
??如果Elvis類是用來實現序列化的,下面的readResolve方法就足以保證單例屬性:


image.png

??此方法忽略反序列化對象,返回初始化類時創建的區分的Elvis實例。因此,Elvis實例的序列化形式不需要包含任何實際數據;所有實例字段都應該聲明為transient。事實上,你依賴于readResolve控制實例,所有具有對象引用類型的實例字段都必須聲明為transient。否則,有決心的攻擊者有可能在運行反序列化對象的readResolve方法之前保護對該對象的引用,使用的技術有點類似于第88項中的MutablePeriod攻擊
??攻擊有點復雜,但其基本思想很簡單。如果單例包含一個nontransient對象引用字段,則在運行單例的readResolve方法之前,將對該字段的內容進行反序列化。這允許一個精心設計的流在對象引用字段的內容被反序列化時“竊取”對原來反序列化的單例對象的引用。
??下面是它的工作原理。首先,編寫一個“stealer”類,該類具有readResolve方法和一個實例字段,該實例字段引用序列化的單例,其中stealer“隱藏”在其中。在序列化流中,用一個stealer實例替換單例的非瞬態字段。現在您有了一個循環性:單例包含了竊取器,而竊取器引用了單例。
??:因為單例包含竊取器,所以當反序列化單例時,竊取器的readResolve方法首先運行。因此,當偷取器的readResolve方法運行時,它的實例字段仍然引用部分反序列化(且尚未解析)的單例。
??:竊取者的readResolve方法將引用從其實例字段復制到靜態字段,以便在readResolve方法運行后訪問引用。然后,該方法為其隱藏的字段返回正確類型的值。如果不這樣做,當序列化系統試圖將竊取器引用存儲到該字段時,VM將拋出ClassCastException。
??要使其具體化,請考慮以下破損的單例:

image.png

??這里是一個“小偷”類,按照上面的描述構造:


image.png

??最后,這是一個丑陋的程序,它反序列化了一個手工制作的流,以生成有缺陷的單例的兩個不同實例。這個程序省略了反序列化方法,因為它與第354頁的方法相同:


image.png

??運行此程序將生成以下輸出,最終證明可以創建兩個不同的Elvis實例(具有不同的音樂品味):


image.png

??您可以通過聲明favoriteSongs字段transient來修復這個問題,但是您最好通過將Elvis設置為單元素枚舉類型來修復它
(第3項).正如ElvisStealer攻擊所證明的,使用readResolve方法來防止攻擊者訪問“臨時”反序列化實例是脆弱的,需要非常小心。
??如果您將可序列化的實例控制類編寫為enum, Java保證除了聲明的常量之外不能有任何實例,除非攻擊者濫用了特權方法,如AccessibleObject.setAccessible。
任何能夠做到這一點的攻擊者都已經擁有足夠的特權來執行任意的本地代碼,所有的賭注都是不可能的。


image.png

??使用readResolve(例如實例控件)并不過時。如果必須編寫一個可序列化的實例控制類,而該類的實例在編譯時是未知的,則不能將該類表示為enum類型。
??重新解析的可訪問性非常重要。如果您將readResolve方法放在最后一個類上,那么它應該是私有的。如果將readResolve方法放在非final類上,必須仔細考慮其可訪問性。如果它是私有的,它將不應用于任何子類。如果它是包私有的,它將只應用于同一包中的子類。如果它是受保護的或公共的,它將應用于不覆蓋它的所有子類。如果readResolve方法是受保護的或公共的,而子類沒有覆蓋它,反序列化子類實例將生成超類實例,這可能會導致ClassCastException
??總之,使用枚舉類型在可能的情況下強制實例控制不變量。如果這是不可能的,并且您需要一個既可序列化又實例控制的類,那么您必須提供一個readResolve方法,并確保該類的所有實例字段都是原始的或transient的。
本文寫于2019.7.24,歷時1天

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • [{"reportDate": "2018-01-23 23:28:49","fluctuateCause": n...
    加勒比海帶_4bbc閱讀 775評論 1 2
  • 目錄: Android:Android 0.*Android 1.*Android 2.*Android 3.*A...
    敲代碼的令狐蔥閱讀 4,010評論 0 2
  • 十七歲的某一天,她說:“同學請問這是七班么”,他現在教室門后面,轉過身答:“是”,那是他們的第一次見面,而在那之后...
    如穎隨行日記閱讀 1,042評論 0 0
  • 算了一次賬,情況非常非常不好!因為虧損很大。要總結一下心得,發現確實不懂,也說不出來個一二三!唯有一點,那就是要有...
    裊裊陽光閱讀 175評論 0 0
  • 今天我們去劉公島留學開心了,我看見了北洋水獅在基地,這就開始進入北洋海獅了,我看見了北洋水獅在基地,這就開始...
    我自己喜歡的事活著閱讀 225評論 0 0