天天看點

Java序列化

 一、 概念

序列化  反序列化 概念可分為 狹義   廣義(個人觀點)

狹義概念:

 指javabean實作serializable 或 externalizable接口 進行byte流和javabean之間互轉。

 java 串行化技術可以使你将一個對象的狀态寫入一個byte 流裡,并且可以從其它地方把該byte 流 裡的資料讀出來,重新構造一個相同的對象。

廣義的概念:

  将javabean對象轉換為便于儲存或傳輸的形式,如轉換為xml 或  json等

  實作這個技術有很多種常見有 1 java 通過實作序列化接口   2 javabean轉換為xml 3 javabean轉換為json

 二 、java對象實作序列化的條件:(java内在序列化機制進行說明)

     1)對象要實作serializable 或 externalizable接口 如果父類不進行序列化(沒有實作接口)則需要提供無參構造函數

     2)序列化 和反序列化對象 serialversionuid 要一緻 

                     最好顯示聲明 serialversionuid = -8832150336623636846l; 因為同一個對象在不同jvm中可能計算出的值是不一緻的

     3)序列化和反序列化的類名要一直 以及包路徑也要一緻

     4)如果要求類名不一緻則可以自己寫方法進行轉換 或 寫 objectinput子類 在下面會進一步介紹

     用途:利用對象的串行化實作儲存應用程式的目前工作狀态,下次再啟動的時候将自動地恢複到上次執行的狀态

      更常用的用途是用于傳輸資料。

   三.實作serializable接口

  objectoutputstream隻能對serializable接口的類的對象進行序列化。

 預設情況下,objectoutputstream按照預設方式序列化,這種序列化方式僅僅對對象的非transient的執行個體變量進行序列化,而不會序列化對象的transient的執行個體變量,也不會序列化靜态變量。

 當objectoutputstream按照預設方式序列化時,具有如下特點

 1)沒有實作接口的父類則不會序列化

 2)聲明為static和transient類型的成員資料不能被串行化。因為static代表類的狀态, transient代表對象的臨時資料;

  當objectoutputstream按照預設方式反序列化時,具有如下特點:

  1) 如果在記憶體中對象所屬的類還沒有被加載,那麼會先加載并初始化這個類。如果在classpath中不存在相應的類檔案,那麼會抛出classnotfoundexception;

  2) 實作了序列化的對象在反序列化時不會調用類的任何構造方法。沒有實作接口的父類則會調用父類無參構造構造器

 注意:在預設的轉換下序列化和反序列化對象名 稱和路徑名要一緻,但對象屬性可以不一緻。

                對于父類是否實作序列化可以不一緻,但同樣的父類名(包名也一緻)都實作序列化那麼serialversionuid就必須一樣

  有些對象中包含一些敏感資訊,這些資訊不宜對外公開。如果按照預設方式對它們序列化,那麼它們的序列化資料在網絡上傳輸時,可能會被不法份子竊取。

 對于這類資訊,可以對它們進行加密後再序列化,在反序列化時則需要解密,再恢複為原來的資訊。

 這就要求對讀出和寫入的流進行處理,java中提供如下方法 ,以objectinputstream為例

 可以寫一個objectinput子類

 /**

  * 寫此類時

  * 隻能調用 父類的無參構造器 因為父類無參構造器會将enableoverride置為true

  * objectinput此時在調用父類的readobject()方法時 會根據enableoverride調用readobjectoverride()

  * 同樣objectout  writeobject() 調用readobjectoverride()

  * 在此方法裡重寫readobjectoverride() writeobjectoverride() 在序列化和反序列化時

  * 對流進行特殊處理

  * 

  */

 public class objectinputstreamnew extends objectinputstream{

  private static objectinput in;

  public objectinputstreamnew(fileinputstream file) throws ioexception, securityexception {

   super();

   this.in = new objectinputstream(file);  

  }

  @override

  public  object readobjectoverride(){

   try {

    object ob = in.readobject();

    propertyutils.copyproperties(this,ob);

   } catch (exception e) {

    e.printstacktrace(); 

   }

   return this;

  } 

 }

四. 可序列化類的不同版本的序列化相容性

  凡是實作serializable接口的類都有一個表示序列化版本辨別符的靜态變量:

 private static final long serialversionuid; 

  以上serialversionuid的取值是java運作時環境根據類的内部細節自動生成的。如果對類的源代碼作了修改,再重新編譯,新生成的類檔案的serialversionuid的取值有可能也會發生變化。

  類的serialversionuid的預設值完全依賴于java編譯器的實作,對于同一個類,用不同的java編譯器編譯,有可能會導緻不同的serialversionuid,也有可能相同。為了提高哦啊serialversionuid的獨立性和确定性,強烈建議在一個可序列化類中顯示的定義serialversionuid,為它賦予明确的值。顯式地定義serialversionuid有兩種用途:

  1) 在某些場合,希望類的不同版本對序列化相容,是以需要確定類的不同版本具有相同的serialversionuid;

  2) 在某些場合,不希望類的不同版本對序列化相容,是以需要確定類的不同版本具有不同的serialversionuid。

 public static void serializabletest() throws exception{

  single.one.dog dogone = new single.one.dog();

  dogone.setname("tomcat");

  dogone.setsex("m");

  fileoutputstream fos = new fileoutputstream("c:/zkg/services.txt");

  objectoutputstream oos = new objectoutputstream(fos);

  oos.writeobject(dogone);

  oos.close();

  fileinputstream in = new fileinputstream("c:/zkg/services.txt");

  objectinputstream ois = new objectinputstream(in); 

  dogtwo  = (single.one.dog)ois.readobject();

  system.out.println(dogtwo.getname());

  ois.close();