Java Serializable接口(序列化)理解及自定義序列化

  1 Serializable接口java

  (1)簡單地說,就是能夠將一個對象(標誌對象的類型)及其狀態轉換爲字節碼,保存起來(能夠保存在數據庫,內存,文件等),而後能夠在適當的時候再將其狀態恢復(也就是反序列化)。serialization 不但能夠在本機作,並且能夠經由網絡操做。它自動屏蔽了操做系統的差別,字節順序等。好比,在 Windows 平臺生成一個對象並序列化之,而後經過網絡傳到一臺 Unix 機器上,而後能夠在這臺Unix機器上正確地重構(deserialization)這個對象。 沒必要關心數據在不一樣機器上如何表示,也沒必要關心字節的順序或者其餘任何細節。
 
另外,還應明白如下幾點:
 
    a. java.io.Serializable接口沒有任何方法屬性域,實現它的類只是從語義上代表本身是能夠序列化的。
 
    b. 在對一個 Serializable(可序列化)對象進行從新裝配的過程當中,不會調用任何構建器(甚至默認構建器)。整個對象都是經過從 InputStream 中取得數據恢復的。
 
    c. 如是要一個類是可序列化的,那麼它的子類也是可序列化的。程序員

(2)serialVersionUID數據庫

serialVersionUID的取值是Java運行時環境根據類的內部細節自動生成的。若是對類的源代碼做了修改,再從新編譯,新生成的類文件的serialVersionUID的取值有可能也會發生變化。
類的serialVersionUID的默認值徹底依賴於Java編譯器的實現,對於同一個類,用不一樣的Java編譯器編譯,有可能會致使不一樣的serialVersionUID,也有可能相同。爲了提升哦啊serialVersionUID的獨立性和肯定性,強烈建議在一個可序列化類中顯示的定義serialVersionUID,爲它賦予明確的值。顯式地定義serialVersionUID有兩種用途:
 
  a. 在某些場合,但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備相同的serialVersionUID;
 
  b. 在某些場合,不但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備不一樣的serialVersionUID。網絡

 

2 自定義序列化:this

      自定義序列化是由ObjectInput/OutputStream在序列化/反序列化時候經過反射檢查該類是否存在如下方法(0個或多個):執行順序從上往下,序列化調用1和2,反序列調用3和4;transient關鍵字當某個字段被聲明爲transient後,默認序列化機制就會忽略該字段。spa

1Object writeReplace() throws ObjectStreamException;能夠經過此方法修改序列化的對象操作系統

2void writeObject(java.io.ObjectOutputStream out) throws IOException; 方法中調用defaultWriteObject() 使用writeObject的默認的序列化方式,除此以外能夠加上一些其餘的操做,如添加額外的序列化對象到輸出:out.writeObject("XX")code

3void readObject(java.io.ObjectInputStream in) throws Exception; 方法中調用defaultReadObject()使用readObject默認的反序列化方式,除此以外能夠加上一些其餘的操做,如讀入額外的序列化對象到輸入:in.readObject()對象

4Object readResolve() throws ObjectStreamException;能夠經過此方法修改返回的對象blog

 

例子:單例模式的類實現序列化接口,若使用默認的序列化策略,則在反序列化返回的對象不符合單利模式(反射建立了新的對象,以下PersonSington對象),能夠經過修改序列化的readResolve來實現自定義序列化返回結果來實現單例對象惟一(至關於1,2,3方法對4的結果毫無做用)。

public class PersonSingleton implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private PersonSingleton(String name) {
        this.name = name;
    };
    private static PersonSingleton person = null;

    public static synchronized PersonSingleton getInstance() {
        if (person == null)
            return person = new PersonSingleton("cgl");
        return person;
    }

    private Object writeReplace() throws ObjectStreamException {
        System.out.println("1 write replace start");
        return this;//可修改成其餘對象
    }

    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        System.out.println("2 write object start");
        out.defaultWriteObject();
//out.writeInt(1); }
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { System.out.println("3 read object start"); in.defaultReadObject();
//int i=in.readInt(); }
private Object readResolve() throws ObjectStreamException { System.out.println("4 read resolve start"); return PersonSingleton.getInstance();//無論序列化的操做是什麼,返回的都是本地的單例對象 } public static void main(String[] args) throws Exception { FileOutputStream out = new FileOutputStream(new File("D://person.dat")); ObjectOutputStream op = new ObjectOutputStream(out); op.writeObject(PersonSingleton.getInstance()); op.close(); FileInputStream in = new FileInputStream(new File("D://person.dat")); ObjectInputStream oi = new ObjectInputStream(in); Object person = oi.readObject(); in = new FileInputStream(new File("D://person.dat")); oi = new ObjectInputStream(in); PersonSinglton person1 = (PersonSinglton) oi.readObject(); System.out.println("sington person hashcode:" + person.hashCode()); System.out.println("sington person1 hashcode:" + person1.hashCode()); System.out.println("singleton getInstance hashcode:" + PersonSingleton.getInstance().hashCode()); System.out.println("singleton person equals:" + (person == PersonSingleton.getInstance())); System.out.println("person equals1:" + (person1 == person)); } }

 

運行結果:


 

1 write replace start
2 write object start
3 read object start
4 read resolve start
3 read object start
4 read resolve start
sington person hashcode:1550089733
sington person1 hashcode:1550089733
sington getInstance hashcode:1550089733
sington person equals:true
person equals1:true


 

3 Externalizable接口

   Externalizable繼承於Serializable,當使用該接口時,序列化的細節須要由程序員去完成。若writeExternal()與readExternal()方法未做任何處理,那麼該序列化行爲將不會保存/讀取任何一個字段。出結果中全部字段的值均爲空。    另外,若使用Externalizable進行序列化,當讀取對象時,會調用被序列化類的無參構造器去建立一個新的對象,而後再將被保存對象的字段的值分別填充到新對象中。因爲這個緣由,實現Externalizable接口的類必需要提供一個無參的構造器,且它的訪問權限爲public。

相關文章
相關標籤/搜索