天天看點

EffectiveJava(筆記十) 序列化序列化74. 謹慎地實作Serializable接口

序列化

對象序列化API, 它提供了一個架構, 用來将對象編碼成位元組流, 并從位元組流編碼中重新建構對象, “将一個對象編碼成一個位元組流”, 稱作将該對象序列化, 相反的處理過程被稱作反序列化, 一旦對象被序列化後, 它的編碼就可以從一台正在運作的虛拟機被傳遞到另一台虛拟機上, 或者被存儲到磁盤上, 提供以後反序列化使用, 序列化技術為遠端通信提供了标準的線路級對象表示法, 也為javaBeans元件結構提供了标準的持久化資料格式

74. 謹慎地實作Serializable接口

  • 實作Serializable接口而付出的最大代價是, 一旦一個類被釋出, 就大大降低了”改變這個類的實作”的靈活性: 如果一個類實作了序列化, 它的位元組流編碼就變成了它的導出的API的一部分, 一旦這個類被廣泛使用, 往往必須永遠支援這種序列化形式, 就好像你必須要支援導出的API的所有其他部分一樣, 如果不努力設計一種自定義的序列化形式, 而僅僅接受了預設的序列化形式, 這種序列化形式将永遠地束縛在改類最初的内部表示法上,序列化會使類的演變收到限制,這種限制的一個例子與流的唯一辨別符有關,通常它被稱為序列版本UID,每個序列化的類都有一個唯一的辨別号與它相關聯,如果沒有在一個名為serialVersionUID的私有靜态final的long域中顯式地指定該符号,系統就會自動地根據這個類來調用一個複雜的運算過程,進而在運作時産生該辨別号。類的成員或者方法改變了,自動産生的序列版本UID也會發生變化,是以,如果沒有聲明一個顯式地序列版本UID,相容性将會遭到破壞,運作時導緻InvalidClassException異常。
  • 實作Serializable的第二個代價是,它增加了出現Bug和安全漏洞的可能性,對象是利用構造器來建立的,序列化機制是一種語言之外的對象建立機制,無論你說否接受了預設的行為,還是覆寫了預設的行為,反序列化機制都是一個“隐藏的構造器”,具備與其他構造器相同的特點,因為反序列化機制中沒有顯式地構造器,是以反序列化過程必須也要保證所有“由真正的構造器建立起來的限制關系”,并且不允許攻擊者通路正在構造過程中的對象的内部資訊,依靠預設的反序列化機制,很容易使對象的限制關系遭到破壞,以及遭受到非法通路。
  • 實作Serializable的第三個代價是,随着類發行新的版本,相關的測試負擔也增加了,當一個可序列化的類被修訂的時候,很重要的一點是,要檢查是否可以“在新版本中序列化一個執行個體,然後在舊版本中反序列化”,随着新的版本的不斷發行,相關的測試工作量也大大增