java對象序列化

概念:

Java 提供了一種對象序列化的機制,一個對象可以被表示爲一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。將序列化對象寫入文件之後,可以從文件中讀取出來,並且對它進行反序列化。也就是說,對象的類型信息、對象的數據,還有對象中的數據類型可以用來在內存中新建對象。

整個過程都是 Java 虛擬機(JVM)獨立的,也就是說,在一個平臺上序列化的對象可以在另一個完全不同的平臺上反序列化該對象。

實現:

一個類實現了Serializable接口,它就可以被序列化

public class Employee implements java.io.Serializable

如果被寫對象的類型是String,或數組,或Enum,或Serializable,那麼就可以對該對象進行序列化,否則將拋出NotSerializableException

JDK中的序列化API:

java.io.ObjectOutputStream代表對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把得到的字節序列寫到目標輸出流中。

java.io.ObjectInputStream代表對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。

只有實現了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

序列化保存對象的狀態,靜態變量屬於類的狀態,因此序列化並不保存靜態變量。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章