天天看點

談談我對序列化與反序列化的了解

一、首先來看看序列化和反序列化是用來幹什麼的?

我們知道對象并不能直接在端與端之間進行通信,是以如果一個對象又需要進行端對端的通信怎麼辦呢?這時候有人就想出了在發送端把對象先轉成可以進行傳輸的位元組,在接收端再通過把位元組轉化成對象的方式進行傳輸。這種将對象轉成位元組的方式就是序列化,而将位元組轉回對象的方式則是反序列化。

一般序列化解決的是将對象持久化到磁盤中,或者對象在網絡中傳輸的問題。

二、下面通過代碼實作對象存儲到磁盤與從磁盤中讀取來了解序列化反序列化

1. 先鍵一個Cat類

public class Cat implements Serializable{
	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = 4669394576337676835L;
	private int age;
	private String name;
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
           

注意:如果不序列化是無法将對象持久化到磁盤的,而序列化對象隻要對象實作Serializable接口就行,若不實作序列化接口就會報如下錯誤

java.io.NotSerializableException: com.java.base.bean.Cat

at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)

at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)

at com.java.base.io.SerializableTest.main(SerializableTest.java:18)

2. 建一個SerializableTest類,實作對象序列化存儲到磁盤中

public class SerializableTest {
	public static void main(String[] args) {
		try {
            //對象将寫入D盤下名為cat.txt的檔案
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/cat.txt"));
			Cat cat = new Cat();
			cat.setAge(2);
			cat.setName("阿鬥");
            //将對象寫入檔案中
			oos.writeObject(cat);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
           

3.建一個DeserializableTest類,将序列化資料讀出,并且轉成Cat對象

public class DeserializableTest {
	public static void main(String[] args) {
		try {
			//讀取之前序列化的檔案cat.txt
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/cat.txt"));
			//将讀取的資料轉為Cat對象的形式
			Cat cat = (Cat) ois.readObject();
			System.out.println("cat age:"+cat.getAge() + " | cat name:"+cat.getName());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}
           

如果,我們的對象有些屬于隐私資訊,不想将他序列化怎麼辦,使用瞬時變量transient,如下表示不會将age屬性序列化。

private transient int age;

當然我們還可以使用另一種方式阻止将我們的隐私資訊序列化,那就是使用實作Externalizable代替Serializable這個方法來解決。如果我們有一些特殊的需求也可以使用這個Externalizable 來實,Externalizable對于Serializable增加了兩個方法,writeObject和readObject,這兩個方法會優先與其他方法先執行。

三、雖然序列化那麼好,但是萬物皆難完美,下面說一下關于序列化的一些不足之處

1、序列化後對象變得不再靈活。

如:在web項目組中提供的一個類Cat的接口服務,在API包調用方法擷取這個類的屬性的時候,在本API建立的Cat中,将原本應該是私有域的age,變成公有域的age。

private int age;public int age

2、如果序列化的類中進行了修改,那麼反序列化的類也要同步修改,否則容易出現bug。

如:在web中提供的Cat類的接口服務,Cat新增了一個屬性sex,如果API的反序列化還是使用原來的序列化格式的話,就會爆出異常,無法接收到新的屬性sex。

3、系統的序列化反序列化是比較耗時的,例如使用Gson對象進行序列化與反序列化的話,速度遠超系統預設的序列化。