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 版本不同, 雖然兼容, 但效能不佳.