一、序列化/反序列化概念
` java是面向對象的語言,對象一般是存活在內存中動態變化的數據。有時候爲了保存和傳輸,需要將內存中存活的動態變化的對象數據轉化成可以固定的字節信息。序列化技術可以實現。將已經固定的對象的字節信息轉換回內存對象的過程就是反序列化的過程。
二、序列化/反序列化應用場景
1、將對象序列化後保存,即持久化
` 將內存中的對象信息序列化後保存到外部存儲設備中。這個過程也稱之爲將對象持久化保存了。再需要的時候可以將持久化保存的對象再讀取回程序內進行反序列化再恢復爲對象,這個過程也稱之爲反持久化。
補充:
` 序列化是持久化的前提。
2、將對象序列化後通過網絡傳輸實現,即RPC
` 將內存中的對象信息序列化後,將字節信息通過網絡發送給其他程序,其他程序收到這些數據後,進行反序列化就可以恢復出對象,得到對象中的信息。
三、常見的序列化/反序列技術
` 序列化/反序列化是在分佈式開發中,其中包括 [持久化]和[RPC] 的基礎,是在分佈式環境下非常常見的操作,所以序列化反序列時性能的好壞直接影響分佈式程序的性能。
1、java自帶的序列化/反序列化技術
(jdk1開始就有了)
優點:簡單,易用,不用導入第三方包
缺點:
效率低下 - 浪費時間
產生的結果數據大 - 浪費空間
只能在java中使用 - 無法跨語言
現實企業中使用很少。
2、其他開源序列化反序列化技術 - AVRO
由APACHE開源組織提供的開源序列化/反序列化技術。
性能優良、體積較小、可以跨語言。
在大數據技術中常見。
3、其他開源序列化反序列化技術 - GoogleProtobuffer
由Google提供的開源序列化/反序列化技術。
性能優良、體積較小、可以跨語言。
在業界廣泛使用。
4、其他開源序列化反序列化技術 - Thrift
由facebook提供的開源序列化/反序列化技術。
性能優良、體積較小、可以跨語言。
在特定領域用的較多。
四 、JAVA自帶的序列化反序列化機制
1、關鍵的類
java.io
類 ObjectInputStream
java.io
類 ObjectOutputStream
java.io
接口 Serializable
2、案例
(1) 要序列化的對象:
public class Person implements Serializable {//標誌可以序列化
private String name;
private int age;
private transient String psw;
//原來沒有這一句,後來添加上,不能序列化成功,標識類的唯一編碼,serialVersionId,可以自動檢測到類信息不同。但是去掉這句話,還可以序列化成功。transient 表示序列化的時候不會被序列化。
public Person() {//空構造
}
public Person(String name, int age,String psw) {
this.name = name;//帶參構造
this.age = age;
this.psw = psw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
}
(2)序列化操作
public class OOS{
public static void main(String[] args) throws Exception {
//1.創建對象
Person p = new Person("ff", 19,"1221");
//2.創建序列化的流
OutputStream out = new FileOutputStream("p.data");
ObjectOutputStream oos = new ObjectOutputStream(out);
//3.序列化對象 輸出到文件 實現持久化
oos.writeObject(p);
oos.flush();
oos.close();
}
}
(3)反序列化操作
public class OIS{
public static void main(String[] args) throws Exception {
//1.創建反序列化流
InputStream in = new FileInputStream("p.data");
ObjectInputStream ois = new ObjectInputStream(in);
//2.進行反序列化操作
Person p = (Person) ois.readObject();
ois.close();
//3.獲取屬性
System.out.println(p.getName());
System.out.println(p.getAge());
System.out.println(p.getPsw());
}
}
注意:
` 回來的是個具有相同信息的對象,不是原來的那個對象,因爲執行完釋放對象,原來的對象已經不存在了。
3、詳解
- 想要被java序列化機制操作的對象的類必須實現Serializable接口
·序列化和反序列化 操作的對象並不是同一個,而是相同類型的不同對象具有相同的信息 - 在java序列化反序列化過程中,實現了Serializable接口的類,需要指定 靜態常量的serialVersionUID屬性,如果不指定虛擬機在編譯過程中會自動生成一個,來指定當前類的序列化版本編號,在序列化時,在產生的字節信息中會保存這個編號,而在反序列化時也會去檢查這個編號,如果不一致則認爲序列化和反序列化時不是同一個類,拋出異常 保證了序列化反序列化時類型的一致安全。
- 在通過網絡將序列化的對象字節信息發送給另一臺機器進行反序列化時,雖然兩端是同樣的類但是並不是同一個類,默認生成的SeriaVersionUid很可能不同,會造成反序列化失敗,此時需要在兩頭都手動指定SeriaVersionUid爲相同的值,纔可以保證正常反序列化。
- 可以在實現了Serializable接口的類的屬性中,用transient關鍵字聲明指定屬性不需要被序列化,這樣在序列化該類的對象時,該屬性會自動被忽略,這在保護對象中一些隱祕信息時非常的有用。