概念:java
Java 提供了一種對象序列化的機制,一個對象能夠被表示爲一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。將序列化對象寫入文件以後,能夠從文件中讀取出來,而且對它進行反序列化。也就是說,對象的類型信息、對象的數據,還有對象中的數據類型能夠用來在內存中新建對象。數組
整個過程都是 Java 虛擬機(JVM)獨立的,也就是說,在一個平臺上序列化的對象能夠在另外一個徹底不一樣的平臺上反序列化該對象。網絡
實現:ide
一個類實現了Serializable接口,它就能夠被序列化工具
public class Employee implements java.io.Serializablespa
若是被寫對象的類型是String,或數組,或Enum,或Serializable,那麼就能夠對該對象進行序列化,不然將拋出NotSerializableException對象
JDK中的序列化API:繼承
java.io.ObjectOutputStream表明對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把獲得的字節序列寫到目標輸出流中。接口
java.io.ObjectInputStream表明對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。ip
只有實現了Serializable和Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自 Serializable接口,實現Externalizable接口的類徹底由自身來控制序列化的行爲,而僅實現Serializable接口的類能夠採用默認的序列化方式 。
對象序列化包括以下步驟:
1)建立一個對象輸出流,它能夠包裝一個其餘類型的目標輸出流,如文件輸出流;
2)經過對象輸出流的writeObject()方法寫對象。
對象反序列化的步驟以下:
1)建立一個對象輸入流,它能夠包裝一個其餘類型的源輸入流,如文件輸入流;
2)經過對象輸入流的readObject()方法讀取對象。
特殊狀況:
對於一個實體類,不想將全部的屬性都進行序列化,有專門的關鍵字 transient:
private transient int name;
對該類序列化時會自動忽略被 transient 修飾的屬性,反序列化後name=0。
更多:
1.序列化ID:
凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量
private static final long serialVersionUID = 1L
情境:兩個客戶端 A 和 B 試圖經過網絡傳遞對象數據,A 端將對象序列化爲二進制數據再傳給 B,B 反序列化獲得對象。
問題:反序列化時老是提示不成功。
解決:虛擬機是否容許反序列化,不只取決於類路徑和功能代碼是否一致,還有兩個類的序列化 ID 是否一致。
序列化 ID 在 Eclipse 下提供了兩種生成策略,一個是固定的 1L,一個是隨機生成一個不重複的 long 類型數據(其實是使用 JDK 工具生成)。隨機生成的序列化 ID 有什麼做用呢,有些時候,經過改變序列化 ID 能夠用來限制某些用戶的使用。
2.不保存靜態變量
public class Test implements Serializable{
public static int staticVar = 5;
}
//序列化,寫入路徑result.obj
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
out.writeObject(new Test());
out.close();
//序列化後修改成10
Test.staticVar = 10;
//反序列化,讀取
ObjectInputStream oin = new ObjectInputStream(new FileInputStream("result.obj"));
Test t = (Test) oin.readObject();
oin.close();
System.out.println(t.staticVar); //結果是10
序列化保存對象的狀態,靜態變量屬於類的狀態,所以序列化並不保存靜態變量。