2016-05-24 72 views
0

外部化相對於序列化的主要優點是外部化僅保留部分對象,而不是序列化時的整個對象。但我認爲我們可以通過自定義序列化來模擬外部化,如果我們不調用defaultWriteObject()方法ObjectOutputStreamwriteObject()可序列化類的方法。因此,如果沒有調用defaultWriteObject()方法並且只持久化可用於實現外部化優勢的可序列化類的實例變量writeObject()方法。通過自定義序列化模擬Java對象外化

下面是一個例子證明上述事情:

package com.test; 

import java.io.*; 

public class Test { 
    public static void main(String[] args) throws FileNotFoundException,  IOException, ClassNotFoundException { 
     Dog dog = new Dog(); 
     System.out.println("before serialization: i = " + dog.i + ", j = " +  dog.j); 

     FileOutputStream fos = new FileOutputStream("abc.ser"); 
     ObjectOutputStream oos = new ObjectOutputStream(fos); 
     oos.writeObject(dog); 

     FileInputStream fis = new FileInputStream("abc.ser"); 
     ObjectInputStream ois = new ObjectInputStream(fis); 
     Dog dog2 = (Dog) ois.readObject(); 
     System.out.println("after deserialization: i = " + dog2.i + ", j = " +  dog2.j); 

    } 

    public static class Dog implements Serializable { 
     int i = 10; 
     int j = 20; 

     private void writeObject(ObjectOutputStream oos) throws IOException{ 
      //oos.defaultWriteObject(); 
      System.out.println("In WriteObject"); 
      oos.writeInt(i); 
     } 

     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 
      //ois.defaultReadObject(); 
      System.out.println("In ReadObject"); 
      i = ois.readInt(); 
     } 
    } 
} 

此代碼的輸出是:

before serialization: i = 10, j = 20 
In WriteObject 
In ReadObject 
after deserialization: i = 10, j = 0 

正如你所看到的,oos.defaultWriteObject()ois.defaultReadObject();被註釋掉,我們堅持和恢復只有實例變量i

那麼,我的假設是否正確,我們可以通過自定義序列化來模擬外化概念?

+0

*「外部化優於序列化的主要好處是外部化只保留部分對象,而不是序列化情況下的整個對象」* ...你在問什麼?序列化表單應該有足夠的信息來保存和恢復對象的狀態。 「對象的一部分」的概念在序列化的背景下沒有意義。如果您指的是「自定義序列化表單」,則內置序列化工具可以創建完全自定義的序列化表單。 – scottb

+0

@scottb我已經用示例更新了我的問題,請查看。 –

回答

0

那麼,我的假設是正確的,我們可以通過自定義序列化來模擬外部化概念 ?

您的假設是正確的,程序員有能力爲他選擇的班級構建任何序列化表格。

Serializable接口是一個標記接口,它向Java運行時環境發信號通知已爲實現類啓用了基於Java的序列化。如果你什麼都不做,Java運行時調用默認的序列化工具,它會從你的類的所有實例字段爲你創建一個序列化表單。

最好序列化形式的一類是其中一個:

  • 僅描述了邏輯其實例的狀態
  • 不含特定實現的細節或元數據
  • 寫入和讀取的最小傳輸和恢復類實例所需的信息

例如,在上面的代碼中,如果同時ij描述了你的對象的有意義的狀態,那麼一個不包含j的序列化表單將會有缺陷,因爲你無法在反序列化之後將對象恢復到其有意義的狀態。

但是,如果i描述有意義的狀態,但j是一個實現細節是不是該對象的邏輯狀態的一部分,那麼這將是消除從流j,以獲得更優的序列化形式的最佳做法。

雖然默認序列化表單(由內置Java序列化工具發出)通常適用於簡單的值類,但更復雜的抽象包含元數據和實現信息,這些信息不應成爲其序列化表單的一部分。

爲了幫助程序員設計了自己的班級最好的序列化格式(如果默認形式是不夠的),Java提供了兩大機制,用於生成對象的最佳序列化形式:

  • 定製系列化
  • Externalizable接口

前者策略允許程序員修改的行爲內置Java序列化工具使用transient KEYWO rd,並掛鉤到諸如readObject()writeObject(),readResolve()等方法中。對於具有必須保護的不變量的不可變值類,特別推薦使用序列化代理。

後者的策略是程序員執行Externalizable而不是SerializableExternalizable本身延伸Serializable)。與Serializable不同,接口Externalizable不是標記接口。它的方法在實現時,旨在讓程序員完全控制如何發射和恢復對象的序列化表單。

「外在經串行化的主要好處是,外化仍然存在只有對象,而不是整個對象 的一部分如在序列化的情況下,」

的序列化形式,其僅包含「對象的一部分」並且不包含重建對象狀態所需的所有信息,因爲它在被序列化之前已經存在,這是一種有缺陷的序列化形式。預計這種形式會在那些依賴序列化進行進程間通信的平臺上引起問題。

+0

感謝您的詳細回覆。因此,無論我們如何使用外部化,我們可以通過自定義序列化來實現同樣的目標,對吧?意思是如果我們不想堅持整個對象,那麼我們可以像使用自定義序列化那樣通過外部化來實現這一點(以問題示例中所示的方式) –