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); 
  single.one.Dog dogOne = new single.one.Dog();
  dogTwo  = (single.one.Dog)ois.readObject();
  System.out.println(dogTwo.getName());
  ois.close();
 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章