一、 概念
序列化 反序列化 概念可分爲 狹義 廣義(個人觀點)
狹義概念:
指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();
}