Java 物件序列化

Java 物件序列化

物件序列化

參考:

http://download.oracle.com/javase/6/docs/platform/serialization/spec/version.html

http://jyhshin.pixnet.net/blog/post/26588157-serialversionuid-%E7%9A%84%E8%AD%A6%E5%91%8A

http://www.javaworld.com.tw/jute/post/view?bid=29&id=134634&sty=1&tpg=7&age=0

 

Glossary:

    serialization: 序列化

    deserialization: 反序列化

    state: 狀態 (屬性值)

    blob: binary large object

    version: 版本 - 分為vm 版本 跟object 版本

    identity of a class: 識別類

    compatible change: 可兼容的變更

    SUIID: Stream Unique Identifier 是一個類別的hash value.

 

應用上我們何時會將物件序列化呢?

(1) 希望能夠將物件的狀態存起來, 後續由其它程式來運轉.

(2) 可能會存在資料庫, 檔案, 甚至用在網路通訊中.

(3) 提供者為序列化, 引用者為反序列化.

 

遇到的挑戰是:

(1) 物件的版本變更在跨vm, 即運轉環境的版本不同, 導致無法反序列化. 如:增加 , 刪除屬性...

(2) 並不是所有的物件都可以把狀態保留下來, 故什麼物件無法序列化?

 

預期的結果:

(1) 在反序列化時, 物件能將相同的名稱屬性正確還原.

(2) 如果物件有繼承關係, 反序列化時亦將其結構還原.

 

vm 識別過程

(1) 用類別完整名稱, 用屬性名稱.

(2) 用SUID來識別類別.

    2-1 若類別有變更如:增加屬性, 在未宣告serialVersionUID 時, 必然有不同的hash value.

    2-2 不同的vm因實作不同, 若未宣告serialVersionUID 時, 可能有不同的hash value.

 

注意事項:

類別變更導致無法反序列化, 分為2種層級

(1) 出現Exception

  屬性Type 改變, 物件名稱改變, 未實作序列化, SUID改變, 或新增/修改/刪除屬性但未宣告SUID …

 

(2) 值未還原而為預設值(如:null)

   簡單的說, 只要名稱對應不到, 如: 變更或增加欄位名稱, 父類別的繼承關係移除,

   Prefix delegate 原本是non-static 改成 static, 或non-transient 改成transient.

 

(3) SUID=-1 與未宣告不同, 未宣告是由VM自行運算Hash value, 而-1 則是有指定SUID, 但若大部份的物件都宣告為-1, 則SUID的比對形同虛設, 兼容性會有疑慮, 因為只要名稱對上了就會反序列, 可能在Runtime時發生未預期的錯誤.

 

(4) 要宣告實作Serializable, 物件才可序列化.

 

(5) 資料庫連線, 檔案串流 ... 是無法序列化的.

 

(6) 若要對集合物件序列化要小心裡頭的物件有沒有序列化.

 

結語:

1. 若物件要序列化一定要宣告SUID.

2. 序列化/反序列化的成本要考慮, 曾經發生因為VM 版本不同, 雖然兼容, 但效能不佳.