1. 程式人生 > >考慮自定義的序列化模式(75)

考慮自定義的序列化模式(75)

一個類實現了Serializable 介面,並且使用了預設的序列化形式

  • 無法擺脫該實現,永遠牽制該類的序列化形式

如果沒有認真考慮預設序列化形式是否合適,不要貿然接受

如果一個物件的物理表示法等同於邏輯內容,可能就適合於預設序列化形式

  • 預設序列化,必須提供一個readObject 方法,來保證約束關係和安全性

如果一個物件的物理表示法與邏輯內容存在實質性區別時,預設序列化存在4個缺點:

  1. 該類匯出API 永遠束縛在該類的內部方表示法上
    • 不方便以後擴充套件
  2. 消耗過多空間
  3. 消耗過多時間
  4. 會引起棧溢位
    • 預設序列化會對物件圖進行一次遞迴遍歷
      ,很容易棧溢位

redaObject 和writeObject

  • 實現這倆引數時,預設呼叫super.defaultReadObject 和 super.defaultWriteObject
    • 如果所有成員變數都是transient(瞬時的),技術上不呼叫問題不大
    • 但是還是推薦呼叫下
    • 但是不呼叫靈活性大增

散列表的序列化

  • 同一JVM無法保證每次執行都一樣
  • 因此預設序列化會到來嚴重的bug
  • 散列表的序列化和反序列化產生的物件,約束關係嚴重破壞

無論是否使用預設序列化形式

  • 呼叫defaultWriteObject方法,transient例項域 都會被序列化

transient 域反序列化後會初始化預設值

  • 如果不能被任何任何transient域所接受,
    • 可以實現redaObject 呼叫defaultReadObject 恢復為可接受的域
    • 也可以將這些域延時到第一次被使用才真正初始化

無論何種序列化形式,如果讀取整個物件狀態的任何其他方法上強制任何同步,

  • 必須在物件序列化上強制這種同步
  • 執行緒安全性考慮
  • 注意鎖的使用,規避資源排列死鎖的危險
  • 宣告顯式的序列化UID
    • 這樣避免序列化版本成為潛在不相容根源
    • 而且如果沒有顯式UID,會高成本產生一個序列化UID
    • 如果希望新版本能夠接受現有序列化例項,就必須使用之前生成的舊版本UID
      • 想要與現有版本不相容,修改序UID即可
      • 前版本例項反序列化會引發 InvalidClassException異常