Java提供了一種對(duì)象序列化的機(jī)制,該機(jī)制中,一個(gè)對(duì)象可以被表示為一個(gè)字節(jié)序列讳苦,該字節(jié)序列包括該對(duì)象的數(shù)據(jù)、有關(guān)對(duì)象的類型的信息和存儲(chǔ)在對(duì)象中的數(shù)據(jù)類型吩谦。
將序列化對(duì)象寫入文件之后鸳谜,可以從文件中讀取出來(lái),并且對(duì)它進(jìn)行反序列化式廷,也就是說(shuō)咐扭,對(duì)象的類型信息、對(duì)象的數(shù)據(jù)滑废,還有對(duì)象中的數(shù)據(jù)類型可以用來(lái)在內(nèi)存中新建對(duì)象蝗肪。
整個(gè)過(guò)程都是Java虛擬機(jī)(JVM)獨(dú)立的,也就是說(shuō)蠕趁,在一個(gè)平臺(tái)上序列化的對(duì)象可以在另一個(gè)完全不同的平臺(tái)上反序列化該對(duì)象薛闪。
類ObjectInputStream和ObjectOutputStream是高層次的數(shù)據(jù)流,他們包含反序列化和序列化對(duì)象的方法俺陋。
注意事項(xiàng)
- 如果一個(gè)類創(chuàng)建的對(duì)象豁延,需要被序列化,那么該類必須實(shí)現(xiàn)接口Serializable腊状,該接口沒有任何定義诱咏,是為了告訴JVM(虛擬機(jī))該類對(duì)象可以被序列化。
- serialVersionUID號(hào)是根據(jù)類的特征和類的簽名算出來(lái)的缴挖。如果可序列化類未顯式聲明 serialVersionUID袋狞,則序列化運(yùn)行時(shí)將基于該類的各個(gè)方面計(jì)算該類的默認(rèn) serialVersionUID 值。原因是計(jì)算默認(rèn)的 serialVersionUID 對(duì)類的詳細(xì)信息具有較高的敏感性,根據(jù)編譯器實(shí)現(xiàn)的不同可能千差萬(wàn)別硕并,這樣在反序列化過(guò)程中可能會(huì)導(dǎo)致意外的 InvalidClassException法焰。
- 被 static 修飾的成員變量無(wú)法序列化,無(wú)法寫到文件倔毙。
- 如果不希望某個(gè)成員變量寫到文件埃仪,同時(shí)又不希望使用 static 關(guān)鍵字, 那么可以使用 transient陕赃。transient 關(guān)鍵字表示瞬態(tài)卵蛉,被 transient 修飾的成員變量無(wú)法被序列化。
準(zhǔn)備工作
- 創(chuàng)建一個(gè)可序列化對(duì)象
import java.io.Serializable; public class Employee implements Serializable { /** * 類的唯一標(biāo)識(shí)么库,是根據(jù)類的特征和類的簽名算出來(lái)的傻丝。 */ private static final long serialVersionUID = -7107394583876641565L; private String name; private String address; private transient int sSN;//該成員變量不需要序列化 private int number; public Employee(String name, String address, int sSN, int number) { super(); this.name = name; this.address = address; this.sSN = sSN; this.number = number; } @Override public String toString() { return "Employee [name=" + name + ", address=" + address + ", sSN=" + sSN + ", number=" + number + "]"; } }
- 創(chuàng)建存儲(chǔ)序列化對(duì)象的本地文件
// 獲取系統(tǒng)默認(rèn)分隔符 final String separator = File.separator; // 獲取系統(tǒng)的主目錄 final String userHomeS = System.getProperty("user.home"); // 序列化對(duì)象的保存路勁 final String objectFilePathS = userHomeS + separator + "Desktop" + separator + "test" + separator + "Employee.ser"; //創(chuàng)建該序列化對(duì)象的文件 File file = new File(objectFilePathS); if (!file.exists()) {//判斷文件是否存在 if (!file.isDirectory()) {//判斷是否是目錄文件 //不是目錄文件,則獲取該文件的父目錄文件诉儒,并創(chuàng)建所有目錄文件 file.getParentFile().mkdirs(); } }
序列化
try (
// 初始化文件輸出流
FileOutputStream fileOutput = new FileOutputStream(objectFilePathS);
// 初始化對(duì)象輸出流
ObjectOutputStream ooStream = new ObjectOutputStream(fileOutput))
{
//初始化要序列化的對(duì)象
Employee employee = new Employee("王二", "南京", 4545565, 1010);
ooStream.writeObject(employee);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
反序列化
try (
//初始化文件輸入流
FileInputStream fileInputStream = new FileInputStream(file);
//初始化對(duì)象輸入流
ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream))
{
//讀取Employee對(duì)象
Employee employee = (Employee)oInputStream.readObject();
System.out.println(employee);
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}