1 什麼是序列化和反序列化
1、定義:
把對象轉換爲字節序列的過程稱爲對象的序列化。
把字節序列恢復爲對象的過程稱爲對象的反序列化。
2、用途:
(1)需要把一些對象持久保存起來,通過序列化將內存種的這些對象轉換爲一系列的字節,就是變成文件。
(2)需要在網絡上傳送字節序列。
2 如何使用
1、先看一下接口Serializable的源代碼。
package java.io;
// 一大堆註釋
public interface Serializable {
}
空的?一個空的方法怎麼實現對象的序列化和反序列化的?其實註釋裏已經提到了,它只是一個標誌而已,告訴JVM實現這個接口的類的對象可被序列化。
2、上代碼
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Student implements Serializable{
private static final long serialVersionUID = 1l;
public static String school = "Java School";
public int id;
public String name;
transient String address;
public Student(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Student{id = "+id+", name = "+name+", address = "+address+"}";
}
}
public class MySeriaalizable{
public static void main(String[] args) {
File file = new File("D:/test.txt");
Student s1 = new Student(1001, "Student1", "幸福路1號");
// 序列化
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(s1);
out.close();
}catch (Exception e) {
e.printStackTrace();
}
// 反序列化
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Student s2 = (Student) in.readObject();
System.out.println(s2.toString());
System.out.println(s1.equals(s2));
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 代碼輸出
Student{id = 1001, name = Student1, address = null}
false
使用起來非常方便,只需要ObjectOutputStream的 writeObject(Object object) 方法實現序列化,ObjectInputStream的readObject() 方法實現反序列化。
代碼輸出address=null?看一下序列化的結果是什麼?
可以看到test.txt文件中還有一些亂碼,這不重要。重要的是可以很清楚的看到裏面有id, name, 但是沒有school, address, 這是因爲被transient修飾的字段不會被序列化;另外static修飾的屬性屬於類,不僅僅屬於某個對象,序列化操作的是對象,所以靜態變量也不會被序列化。
3 爲什麼使用serialVersionUID
serialVersionUID非必需但很有必要,如果自己不聲明,JVM會動態的生成。原則上,序列化後的數據中的serialVersionUID與當前類當中的serialVersionUID一致時,對象才能夠反序列化成功。在序列化過程種,系統將serialVersionUID寫入到序列化的文件中,反序列化時,首先檢測文件中的serialVersionUID和當前類的serialVersionUID是否一致,如果一致則反序列化成功,否則報錯:java.io.InvalidClassException。
靠JVM動態聲明serialVersionUID,類發生改變serialVersionUID會發生變化,且不同的編譯器生成的serialVersionUID也會不同。看一下示例,在部分2中代碼基礎上,去掉serialVersionUID進行序列化後,對Student類增加一個屬性(修改或者刪除也一樣),然後對序列化結果直接進行反序列化。
class Student implements Serializable{
//private static final long serialVersionUID = 1l;
public static String school = "Java School";
public int id;
public String name;
transient String address;
public String newStr;
...... // 和部分2代碼相同
}
public class MySeriaalizable{
public static void main(String[] args) {
File file = new File("D:/test.txt"); // 讀取動態生成serialVersionUID序列化的結果
Student s1 = new Student(1001, "Student1", "幸福路1號");
// 反序列化
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Student s2 = (Student) in.readObject();
System.out.println(s2.toString());
System.out.println(s1.equals(s2));
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
java.io.InvalidClassException: mytest.Student; local class incompatible: stream classdesc serialVersionUID = -5603698407479578026, local class serialVersionUID = 970959418018661672
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:621)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at mytest.MySeriaalizable.main(MySeriaalizable.java:61)
錯誤提示:stream classdesc serialVersionUID=-5603698407479578026, local class serialVersionUID=970959418018661672,兩次動態生成的serialVersionUID不同。
如果自己聲明serialVersionUID,則不會出現這個錯誤,在反序列化生成的對象只有未發生改變的屬性的賦值,比如將“name”改名爲“name1”後的反序列化結果爲:
Student{id = 1001, name = null, address = null}
false