Java保存對象

1 將序列化對象寫入文件

一般流程:

//可能會產生異常
try {
			//打開文件
			FileOutputStream fileStream=new FileOutputStream("MyGame.ser");
			//創建對象輸出流
			ObjectOutputStream oStream=new ObjectOutputStream(fileStream);
			//寫入對象
			oStream.writeObject(new Integer(1));
			//關閉對象輸出流
			oStream.close();
			//關閉文件流
			fileStream.close();
}catch (Exception e) {
			e.printStackTrace();// : handle exception
}

  1. 對象存儲了什麼?

在存儲對象時,我們想的是恢復對象後能和存儲時有一樣的狀態。但是如果在對象中有其它對象成員呢,我們知道在對象中保存的實際是其它對象的引用,真正的對象在堆上其它地方。如果只保存此對象的引用,顯然在恢復時會出錯誤。

序列化程序會將對象版圖上的所有東西存儲起來。被對象的實例變量所引用的所有對象都會被序列化。
例如:zoo對象中有Lion[] lionArray對象,lionArray對象中又有多個lion,那麼在存儲zoo時,lionArray和其中的lion都會被序列化存儲。

  1. 可序列化接口Serializable與不可序列化關鍵詞transient

如果要讓自己設計的類可以被序列化存儲,就實現Serializable接口,不需要實現任何方法。實現了此接口的類,其子類也可以序列化。

如果要讓一個類可序列化,那麼此類中的所有成員都應該是可序列化的,即整個對象版圖都必須正確地序列化,不然就全部失敗。

如果某實例變量不能不應該被序列化,就把它標記爲transient(瞬時)的。

某類可序列化但其父類不可序列化的情況:
當對象被還原且它的父類不可序列化時,父類的構造函數會跟創建新的對象一樣執行。

有多個引用指向同一個對象的情況:
只有一個對象會被存儲,恢復後原引用仍指向同一對象。

如果某個實例被標記爲transient的:
那麼在恢復時會默認設爲null,如果該值很重要,可通過其它方法保存其值,待恢復後再將值賦給它。

2 解序列化:還原對象

一般流程:

try {
			//打開文件
			FileInputStream fileStream=new FileInputStream("MyGame.ser");
			//創建對象輸入流
			ObjectInputStream iStream=new ObjectInputStream(fileStream);
			//讀取對象
			Object oneObject=iStream.readObject();
			//轉換對象
			Integer aInteger=(Integer)oneObject;
			//關閉對象輸入流
			iStream.close();
			//關閉文件輸入流
			fileStream.close();
		} catch (Exception e) {
			e.printStackTrace();// TODO: handle exception
	}
  1. 對象恢復時發生了什麼

在恢復對象時,java虛擬機首先通過存儲信息判斷對象的class類型,如果無法加載該類型則拋出異常。

新的對象被配置在堆上,但其構造函數不會執行,如果其某個父類是不可序列化的,則該父類及其之上的父類的構造函數會執行。

未被標記爲transient的變量會恢復成存儲時的內容,被標記爲transient的變量會被設置爲0、false或null。

靜態變量不會被序列化。

3 版本控制

如果對象被保存後,它原來的類被修改了,這樣在讀取對象時就有可能會出錯。例如原來類中的某個變量被刪除了,或者類型被修改等等。有些修改會損害解序列化,有些不會。

會損害解序列化的修改 通常不會有事的修改
刪除實例變量 加入新的實例變量(會使用默認值)
改變實例變量的類型 在繼承層次中加入新的類
將非瞬時的實例變量改爲瞬時的 從繼承層次中刪除類
改變類的繼承層次 不會影響解序列化程序設定變量值的存取層次修改
將類從可序列化改成不可序列化的 將實例變量從瞬時改成非瞬時(會使用默認值)
將實例變量改成靜態的

每當對象被序列化的同時,該對象都會被加上一個類的版本識別ID,被稱爲serialVersionUID,在還原對象時,會對比對象與java虛擬機上類的serialVersionUID,只有相同纔會判定爲相同的類。

在修改了類之後通常修改了類之後其serialVersionUID會發生改變,也就是還原對象時會找不到其類型。有一個解決方法是將serialVersionUID放在類中,使其固定。

使用serialver工具可以查詢某個類的serialVersionUID,再將其賦給類中的static final long serialVersionUID變量

public class Dog{
	static final long serialVersionUID=-3480159834908509L;
	//其它代碼
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章