1. 程式人生 > >Serializable序列化和反序列化

Serializable序列化和反序列化

一、序列化和反序列化的概念

把物件轉換為位元組序列的過程稱為物件的序列化。
把位元組序列恢復為物件的過程稱為物件的反序列化。 

serialization 序列化 : 將物件轉化為便於傳輸的格式, 常見的序列化格式:二進位制格式,位元組陣列,json字串,xml字串。
deserialization 反序列化:將序列化的資料恢復為物件的過程。 

就像淘寶上買一個大件,運輸的時候當然到拆分成一小塊一小塊,這就是序列化,到買家手中再進行組裝就是反序列化。

二、序列化和反序列化的作用

 資料都是以二進位制序列的形式在網路上進行傳送,就需要Java序列化與反序列化

(1)永久性儲存物件,儲存物件的位元組序列到本地檔案或者資料庫中; 
(2)通過序列化以位元組流的形式使物件在網路中進行傳遞和接收; 
(3)通過序列化在程序間傳遞物件;

三、java中的序列化與反序列化 

java.io.ObjectOutputStream代表物件輸出流,它的writeObject(Object obj)方法可對引數指定的obj物件進行序列化,把得到的位元組序列寫到一個目標輸出流中。
java.io.ObjectInputStream代表物件輸入流,它的readObject()方法從一個源輸入流中讀取位元組序列,再把它們反序列化為一個物件,並將其返回。 

只有實現了Serializable和Externalizable介面的類的物件才能被序列化。Externalizable介面繼承自 Serializable介面,實現Externalizable介面的類完全由自身來控制序列化的行為,而僅實現Serializable介面的類可以 採用預設的序列化方式 。
  物件序列化包括如下步驟:
  1) 建立一個物件輸出流,它可以包裝一個其他型別的目標輸出流,如檔案輸出流;
  2) 通過物件輸出流的writeObject()方法寫物件。

  物件反序列化的步驟如下:
  1) 建立一個物件輸入流,它可以包裝一個其他型別的源輸入流,如檔案輸入流;
  2) 通過物件輸入流的readObject()方法讀取物件。 

實現Serializable 介面的時候,一定要給這個 serialVersionUID 賦值 

當實現java.io.Serializable介面的類沒有顯式地定義一個serialVersionUID變數時候,Java序列化機制會根據編譯的Class自動生成一個serialVersionUID作序列化版本比較用,這種情況下,如果Class檔案(類名,方法明等)沒有發生變化(增加空格,換行,增加註釋等等),就算再編譯多次,serialVersionUID也不會變化的。如果不顯示的去寫版本號,那麼就可能造成反序列化時,因為類改變了(怎加了方法,修改了方法名等)而生成了不一樣的版本號,那麼原先序列化的位元組序列將無法轉成該版本的物件,因為版本不一致嘛。所以一定要顯示的去設定版本號。

詳解見Java 之 Serializable 序列化和反序列化

 transient 修飾的屬性,是不會被序列化的。

雖然Java的序列化能夠保證物件狀態的持久儲存,但是遇到一些物件結構複雜的情況還是比較難處理的,下面是對一些複雜情況的總結:

  • 當父類實現了Serializable介面的時候,所有的子類都能序列化
  • 子類實現了Serializable介面,父類沒有,父類中的屬性不能被序列化(不報錯,但是資料會丟失)
  • 如果序列化的屬性是物件,物件必須也能序列化,否則會報錯
  • 反序列化的時候,如果物件的屬性有修改或則刪減,修改的部分屬性會丟失,但是不會報錯
  • 在反序列化的時候serialVersionUID被修改的話,會反序列化失敗
  • 在存Java環境下使用Java的序列化機制會支援的很好,但是在多語言環境下需要考慮別的序列化機制,比如xml,json,或則protobuf