使用java以來,序列化隨處可見,至於為什麼要用序列化、序列化能解決什麼問題,作為一個普通的碼農,一般不怎麼會去深入研究,由於最近在看mina和公司內部涉及到nio框架的一些源碼,裡面涉及到hession、java這兩種序列化,至於hession序列化為什麼會誕生以及在apache項目中使用如此廣泛,以及java本身序列化存在哪些缺陷,甚是不解,為瞭解答上面拋出來的疑惑,以及進一步瞭解java的序列化機制,這裡開個小頭,從java的序列化接口Serializable開始說起
jdk包裡的Serializable接口的註釋主要說明瞭以下幾點:
1.類通過實現Serializable接口來啟用序列化,否則該類的任何狀態將無法被序列化,同時也無法用於反序列化
2.若繼承的父類沒有實現Serializable接口,但是又想讓子類可序列化,有三個註意事項:
a).子類實現Serializable接口
b).子類必須有可訪問的無參構造方法,用於保存和恢復父類的public或protected或同包下的package字段的狀態,否則在序列化或反序列化時會拋出RuntimeException異常
c).對於序列化後的子類,在進行反序列化時,理論上無法初始化父類中private(不可訪問)對象變量的狀態或值
3.在對可序列化類中的屬性進行序列化時,如果遇到不可序列化的對象變量,此時會針對不可序列化的類拋出NotSerializableException異常
4.對於可序列化的非數組類,強烈建議顯示聲明static型、long型、final型serialVersionUID字段用於標識當前序列化類的版本號,否則在跨操作系統、跨編譯器之間進行序列化和反序列化時容易出現InvalidClassException異常
5.對於可序列化類中的static、transient對象變量,在序列化時無法保存其狀態或值,static對象變量在反序列化時取得的值為當前jvm中對應類中對應static變量的值,而transient(瞬態)關鍵字則一般用於標識那些在序列化時不需要傳遞的狀態變量
簡單的測試代碼:
01
import java.io.FileInputStream;
02
import java.io.FileNotFoundException;
03
import java.io.FileOutputStream;
04
import java.io.IOException;
05
import java.io.ObjectInputStream;
06
import java.io.ObjectOutputStream;
07
import java.io.Serializable;
08
09
/**
10
* 序列化測試
11
*
12
* @author sume
13
*
14
*/
15
public class SerializableImpl implements Serializable {
16
17
private static final long serialVersionUID = -6433786313435044319L;
18
19
static String staticVal = "static1";
20
transient String transientVal = "transient1";
21
String val = "val1";
22
23
/**
24
* main
25
*/
26
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
27
// 序列化
28
SerializableImpl sila1 = new SerializableImpl();
29
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("Serializable.txt"));
30
objectOutputStream.writeObject(sila1);
31
objectOutputStream.close();
32
33
// 反序列化
34
SerializableImpl.staticVal = "static2";
35
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("Serializable.txt"));
36
SerializableImpl sila2 = (SerializableImpl) objectInputStream.readObject();
37
objectInputStream.close();
38
39
// 比較各個屬性的值
40
System.out.println(sila2.staticVal);
41
System.out.println(sila2.transientVal);
42
System.out.println(sila2.val);
43
}
44
}
輸出結果:
1
static2
2
null
3
val1
從輸出結果可以看出:
1.反序列化後類中static型變量staticVal的值為當前jvm中對應static變量的值,為:static2,而不是序列化時的值:static1
2.transient關鍵字標識的變量的狀態並沒有在序列化中被保存,因此反序列化後
transientVal變量的值為null
3.第三個為常見的對象狀態在序列化和反序列化過程中的傳遞
簡單印證瞭前面所說的幾點內容
另外:對於在序列化和反序列化過程中需要對類進行特殊處理或需要指定替代對象的操作,
本文沒有涉及到,會在後面進一步討論時給出
作者“sumekey的博客”