什么是Java對象序列化:
- Java平臺允許我們在內存中創建可復用的Java對象,但一般情況下,只有當JVM處于運行時,這些對象才可能存在,即這些對象的生命周期不會比JVM的生命周期更長。
- 在現實應用中,就可能要求在JVM停止運行之后能夠保存(持久化)指定的對象,并在將來重新讀取被保存的對象。Java對象序列化就能夠幫助我們實現該功能。
- 除了在持久化對象時會用到對象序列化之外,當使用RMI(遠程方法調用),或在網絡中傳遞對象時,都會用到對象序列化。
- 使用Java對象序列化,在保存對象時,會把其狀態保存為一組字節,在未來,再將這些字節組裝成對象。必須注意地是,對象序列化保存的是對象的"狀態",即它的成員變量,對象序列化不會關注類中的靜態變量。
怎么進行對象序列化:
(1)Java中,只要一個類實現了Serializable接口,那么它就可以被序列化;
(2)如果一個類中有些字段不希望被序列化,例如如果一個用戶有一些敏感信息(如密碼),為了安全起見,不想被記錄在文件中被傳輸,這些信息對應的變量加上transient關鍵字就可以了; 序列化對象的時候,這個屬性就不會序列化到指定的目的地中(file中)。
使用ObjectOutputStream將對象序列化/ObjectInputStream將對象反序列化:
java.io中的類ObjectInputStream 和ObjectOutputStream是高層次的數據流,它們包含序列化和反序列化對象的方法。他們呢是InputStream/OutputStream的直接子類。
-
例子:
首先我們自定義一個類:private static final long serialVersionUID = 1L; private String name; private int age; private transient int password; private Gender gender; public Person(String name, int age, int password, Gender gender) { super(); this.name = name; this.age = age; this.password = password; this.gender = gender; } @Override public String toString() { String str = "[" + "name : " + name + "\r\n" + "age : " + age + "\r\n" + "password :" + password + "\r\n" + "gender : " + gender + "]"; return str; }
其中Gender屬性是一個enum(枚舉)類,查閱API文檔我們知道enum實現了Serialable接口所以該屬性也可以被序列化;
enum Gender {MAIL,FEMAIL}
下面我們使用ObjectOutputStream和ObjectInputStream實現序列化反序列化;
public class Test {
public static void main(String[] args) {
String fileName = "D://Person.ser";
File file = new File(fileName);
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
Person person = new Person("lisi", 16, 1111111, Gender.MAIL);
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(person);
oos.close();
ois = new ObjectInputStream(new FileInputStream(file));
Object p= ois.readObject();
ois.close();
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
serialVersionUID字段意義:
在實際應用中我們常遇到要修改Person類的情況,由于Person之前已經實現了Serialable接口,如果在序列化之后,Person這個類發生了改變,比如,多了一個成員變量。我們經過試驗可以得到這樣的結果:
Exception in thread “main” java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = xxxxxxxx, local class serialVersionUID = yyyyyyyyyy ;
意思就是說,文件流中的class和classpath中的class,也就是修改過后的class,不兼容了,處于安全機制考慮,程序拋出了錯誤,并且拒絕載入。
出現這樣的結果就是,我們如果不知名被序列化的對象的serialVersionUID字段時候,java會給我們自動生成一個serialVersionUID,帶改變后又給我們生成了另一個serialVersionUID,導致了反序列化失敗。
此時我們就需要對該類自己指定一個serialVersionUID值,指定后再修改就不會出現上述問題了。(當我們使用了如Eclipse這樣的編譯器時,編譯器會提示我們生成該字段,不生成的話就會報出警告)
參考資料:
transient:
對象序列化為何要定義serialVersionUID的來龍去脈
http://lenjey.iteye.com/blog/513736)http://lenjey.iteye.com/blog/513736
理解Java對象序列化
http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html