【零碎JAVA】java序列化

在學習javaIO技術的時候,我們能夠在java.io包中看到有ObjectInputStream,ObjectOutputStream兩個類,從他們名字的結構上我們不難發現,他們分別是InputStream,OutputStream的子類,他們的功能是對對象的讀寫。查閱java API,文檔上是這麼描述的:

        ObjectInputStream:ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化。

        ObjectOutputStream:ObjectOutputStream 將 Java 對象的基本數據類型和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構)對象。

通俗一點講,ObjectOutputStream可以將對象寫入OutputStream流中(比如文件,已達到對象的持久化存儲),我們知道,java中對象存儲在對內存中,因此,ObjectOutputStream是將對內存中的對象寫入OutputStream流中。相反的,ObjectInputStream的作用是可以將對應的OutputStream流中的數據重新加載進內存。

 

 

Serializable

        自習查閱ObjectInputStream,ObjectOutputStream的api文檔,裏面都講到了這麼一句比較類似的話,就是隻有支持 java.io.Serializable 或 java.io.Externalizable 接口的對象才能進行相關的操作,我們點擊查看一下Serializable,他沒有提供任何構造方法,以及成員函數,意思就是實現Serializable接口,我們無序實現任何Serializable中的方法。實際上,實現Serializable接口只是對該類進行了一次標記,標記這個類是可以被序列化的。

 

 

ObjectOutputStream 內存對象寫入文件

        下面,我們看一下如何使用ObjectOutputStream,舉一個簡單的例子,講堆內存中的對象寫入文件,達到一個數據持久化的功能。

        首先,我們創建一個Person類,我們試圖將這個Person的類對象寫入文件。這個Person類必須實現Serializable接口。

	import java.io.*;

	class Person implements Serializable
	{
		public String name;
		public int age;
		public Person(String name, int age){
			this.name = name;
			this.age = age;
		}

		public String toString(){
			return this.name + ":" + this.age;
		}
	}

        我們寫一個對象讀寫的測試類,這個測試類另起一個文件,不要將他與Person寫在同一個文件,將對象寫入本地文件的關鍵代碼如下,異常的捕獲,處理就不寫出來了:

	ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
	oos.writeObject(new Person("zhangsan", 28));
	oos.close();

        此處,我將這個對象寫入本地的object.txt文件中,編譯執行代碼,我們會發現object.txt文件產生了,打開後可以看到一串看不懂的字符,說明寫入成功了。

 

 

ObjectOutputStream 將本地文件中的對象重新加載進內存

        下面,我們看一下如何將本地文件中對象加載進內存,以供程序使用,他的關鍵代碼如下所示,異常的捕獲處理就不寫出來了:

	ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
	Person p = (Person)ois.readObject();
	System.out.println(p);

        編譯代碼,執行,我們就能夠看到Person對象的內容在控制檯打印出來了。


 

序列化的一些問題

        問題1.如果對象已經存儲與本地文件,但是後期修改了對象所屬類的結構,再次使用ObjectInuputStream會有什麼問題?

            我們將Person類中的name屬性設置成private,然後編譯Person重新生成.class文件,然後執行本地對象的讀操作(此時Object.txt存放的是之前Person的對象,現在生成了新的Person.class文件,兩者肯定是有區別的),我們會發現如下錯誤:

	Exception in thread "main" java.io.InvalidClassException: Person; local class in
	compatible: stream classdesc serialVersionUID = -1945702287438740193, local clas
	s serialVersionUID = -7312174078679069023

            他的意思是說本地Person字節碼的serialVersionUID與流中的(即Object.txt)serialVersionUID不一致。這說明ObjectInputStream,ObjectOutputStream對對象進行讀寫的時候會判斷.class中的serialVersionUID與流中的serialVersionUID是否一致,若不一致說明不匹配,就會報以上錯誤,提高了程序的可靠性。我們可以將[ANY-ACCESS-MODIFIER] static final long serialVersionUID屬性作爲類屬性寫死。

 

        問題2.爲什麼static聲明的屬性不能被序列化?

            我們修改Person類,添加靜態的addr屬性,修改構造方法,以及toString方法

	import java.io.*;

	class Person implements Serializable
	{
		public  String name;
		public int age;
		public static String addr = "beidajie112";
		public Person(String name, int age, String addr){
			this.name = name;
			this.age = age;
			this.addr = addr;
		}

		public String toString(){
			return this.name + ":" + this.age + ":" + this.addr;
		}
	}

            重新寫入文件

	<span style="color:#ff0000;">oos</span>.writeObject(new Person("zhangsan", 28, "changanjie123"));

            執行讀取文件,並在控制檯輸出,我們發現輸出的地址欄是“beidajie112”,而不是我們後來的“changanjie123”,說明addr這個屬性並沒有存入文件,他獲取的是默認的addr值,因爲靜態對象並不存放在對內存中,而ObjectOutputStream是將對內存中的對象序列化,所以static的屬性不能被序列化!

            如果我們不想讓我們的非靜態成員被序列化,我們可以給該屬性加上transient的關鍵字,來達到這個效果。

 

 

 

 

 

發佈了36 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章