本文為原創文章,歡迎轉載,但請注明出處http://www.cnblogs.com/yexiubiao/p/5014015.html,未在文章頁面明顯位置給出原文連接的,將保留追究法律責任的權利。
通過java的ObjectOutputStream、ObjectInputStream類能對實現了Serializable接口的對象實現序列化與反序列化,如下
import java.io.Serializable; import com.alibaba.fastjson.JSON; public class Person implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String name; public Person() { super(); } public Person(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() {
// 這里偷懶用了Fastjson return JSON.toJSONString(this); } }
序列化(寫入對象):
反序列化(讀取對象)
通過這樣就能把一個對象存入磁盤里,並且能讀取到內存里
以上是Serializable的基本用法,接下來介紹一些使用中的小細節(關於以下出現的術語,保存對象與序列化,讀取對象與反序列化都分別是同一個意思)。
1,將對象序列化到本地后,對類進行修改,增加或減少字段(成員變量)或交換字段位置,然后反序列化之前保存的對象,都不會報錯。
例如去掉id字段並增加newValue字段:
此時能正常讀取之前序列化的對象(newValue字段因為值是null,這里默認不展示):
2,改變serialVersionUID值后,讀取時發生異常
java.io.InvalidClassException: com.ye.test.model.Movie;
Incompatible class (SUID): com.ye.test.model.Movie: static final long serialVersionUID =1L; but expected com.ye.test.model.Movie: static final long serialVersionUID =2L;
因為serialVersionUID值改變后,類定義的版本變化了,所以讀取老版本對象將可能不兼容新對象,因此系統拋出異常
讀取為null:

3,保存的時候對象有serialVersionUID,然后刪除這個字段,再次讀取

則讀取時serialVersionUID會被賦值一個自動生成的值
這個值根據類的成員變量方法定義等算出,增減成員變量或者增減方法都會導致這個值的改變
但是如果增加空格,交換成員變量位置等都不會導致這個值被改變
java.io.InvalidClassException: com.ye.test.model.Movie; Incompatible class (SUID): com.ye.test.model.Movie: static final long serialVersionUID =1L; but expected com.ye.test.model.Movie: static final long serialVersionUID =-
6926675519878447654L;
也就是說,如果我們的Person類沒有聲明serialVersionUID變量,則以后這個類只要涉及到增減成員變量或者增減方法都會導致讀取對象時不兼容。當然方法位置的調整不會影響。
4,如果先序列化保存一個對象到磁盤,然后修改這個類的定義,將其繼承至一個基類(基類沒有實現Serializable接口),則會報錯
java.io.InvalidClassException: com.ye.test.model.BaseMovie;
IllegalAccessException
at java.io.ObjectStreamClass.
resolveConstructorClass(ObjectStreamClass.java:692)
如果基類實現了Serializable接口,則能正常讀取
5,如果基類已經實現了Serializable接口,則子類無需再次實現(當然子類再次實現也沒關系)
6,父類的serialVersionUID成員變量對子類沒有影響,即使他是public的,所以反序列化時能不能兼容只會跟子類的serialVersionUID對象數值相關。
也就是說開發中如果我們定義的類已經修改,需要告訴系統我們的類已經不再兼容老版本,則需要修改子類的serialVersionUID版本號而不是父類。
7,如果子類實現Serializable接口,父類沒有實現,則只可以執行序列化,不能執行反序列化,執行反序列化時報錯信息同4
總結:
1,如果存在繼承關系,則只需在基類實現Serializable接口即可
2,serialVersionUID變量需在子類定義,父類定義沒有意義(父類定義serialVersionUID用來消除編譯警告信息也沒關系)
3,如果沒有定義serialVersionUID變量,則系統在保存或讀取時會根據類結構自動算出一個值賦予serialVersionUID,如果類結構沒有變化,那么這個值則是固定的,所以還是盡量使用自定義的值比較便於維護。
4,如果需求變更導致類結構調整,那么如果需要繼續讀取老版本對象的話, 則不要修改serialVersionUID的版本號,如果需要使用全新的數據而拋棄之前保存在磁盤里的對象,則修改serialVersionUID版本號,系統會默認讀取為null。相當於之前沒有保存過。
最后附上demo,有興趣的話可以自己測試下。