在實際開發中,我們會將一個對象寫入到一個文件中,進行持久化. 那麼這個類必須要實現一個Serializable接口,才能寫入!那麼java是怎麼進行持久化保存對象呢?
Java序列化就是將一個對象轉化成一串二進制表示的字節數組,通過保存或轉移這些字節數據來達到持久化的目的。需要持久化,對象必須繼承java.io.Serializable接口。反序列化則是相反的過程,將這個字節數據再重新構造成對象。我們知道反序列化時,必須有原始類作爲模板,才能將這個對象還原,從這個過程我們可以猜測,序列化的數據並不像class文件那樣保存類的完整的結構信息。
那麼序列化的數據到底都含有哪些信息,如下面的代碼所示:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = 1396269444885402064L;
public int num = 3190;
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("student.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
oos.writeObject(s);
oos.flush();
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
序列化的文件二進制字節數據如下:
解析:
ac ed: STREAM_MAGIC 聲明使用了序列化協議。
00 05: STREAM_VERSION 序列化協議版本。
73: TC_OBJECT 聲明這是一個新的對象。
72: TC_CLASSDESC聲明這裏開始一個新class。
72 00 07 53 74 75 64 65 6E 74: Student的完整類名。
13 60 8B A9 91 20 51 D0: serialVersionUID,序列化ID,如果沒有 指定,則會由算法隨機生成一個8字節的ID。
02: 標記號,該值聲明該對象支持序列化。
00 01: 該類所包含的域的個數爲1。
49:域屬性,49代表“I”,也就是Int類型。
00 03:域名字的長度,爲3。
6e 75 6d: num屬性的名稱。
78:TC_ENDBLOCKDATA,對象塊結束的標誌。
70:TC_NULL,說明沒有其他超類的標誌.
00 00 05 6e:3190的數值。
雖然Java的序列化能夠保證對象狀態的持久保存,但是遇到一些對象結構複雜的情況還是比較難處理的,下面是對一些複雜的對象情況的總結:
1.當父類繼承Serializable接口時,所有子類都可以被序列化。
2.子類實現了Serializable接口,父類沒有,父類的屬性不能序列化(不報錯,數據會丟失),但是在子類中的屬性仍能正確序列化。
3.如果序列化的屬性是對象,則這個對象也必須實現Serializable接口,否則會報錯。
4.在反序列化時,如果對象的屬性有修改或刪除,則修改的部分屬性會丟失,但不會報錯。