2010-01-22 28 views
11

我想序列化第三方庫中有一個特定的類。我會如何去做這件事?在java中,我如何序列化一個沒有標記爲可序列化的類?

我假設我將不得不編寫一個方法,該方法需要一個類的對象並使用反射來獲取私有成員值。然後爲了反序列化,我將使用反射來將值返回。

會這樣嗎?有更容易的方法嗎?

+0

您是否需要它與w/future版本兼容? – 2010-01-22 01:15:13

+0

不需要,它不需要與將來的版本兼容。 – Kyle 2010-01-22 01:38:49

+0

你只是想要堅持數據?如果是這樣,爲什麼不使用JAXB? – Boltimuss 2010-01-22 03:13:32

回答

12

您可以使用實現Serializable的傳輸對象,並具有與第三方對象相同的字段。讓傳輸對象實現返回原來的第三方類的對象的方法,就大功告成了:

僞代碼:

class Thirdparty{ 

    int field1; 
    int field; 
} 

class Transfer implements Serializable{ 

    int field1; 
    int field2; 

    /* Constructor takes the third party object as 
     an argument for copying the field values. 
     For private fields without getters 
     use reflection to get the values */ 
    Transfer (Thirdparty orig){ 
     this.field1=orig.field1; 
     this.field2=orig.field2; 
    } 

    ThirdParty getAsThirdParty(){ 
     Thirdparty copy=new ThirdParty(); 
     copy.field1=this.field1; 
     copy.field2=this.field2; 
     return copy; 
    } 

    /* override these methods for custom serialization */ 
    void writeObject(OutputStream sink); 
    void readObject(InputStream src); 
} 

你一定要確保成員被正確序列化,如果你有任何特殊的成員對象。

或者,如果第三方類不是最終的,你可以擴展它,讓它實現Serializable並編寫你自己的writeObject和readObject方法。

入住這裏有些系列化的相關信息:

Serialization Secrets

+0

謝謝,這似乎很好,我該如何處理私有成員變量?有沒有簡單的方法,或者我需要反思? – Kyle 2010-01-22 02:36:39

+0

yep反射是我知道訪問不可見域的唯一方法。 :/ – fasseg 2010-01-22 02:59:36

2

你需要將它包裝成的東西做的序列化。

理想情況下,第三方類支持一些其他形式的序列化,例如XML序列化(基於bean屬性)。如果不是,你必須推出自己的。無論是涉及反射還是隻是獲取者,setter和構造函數都依賴於類。

在任何情況下,包裝器都會將對象轉換爲byte []或String或其他東西,並將其寫入序列化輸出中。在反序列化過程中,它從數據中重建對象。

這兩種方法的包裝必須實現的

private void writeObject(java.io.ObjectOutputStream out) 
throws IOException 
private void readObject(java.io.ObjectInputStream in) 
throws IOException, ClassNotFoundException; 
1

這很大程度上取決於第三方類的性質。它是否是最終的,它是否有一個無參數構造函數,您可以構造給定的已知值,還是由另一個類構造,它本身是否包含非序列化成員?

最簡單的方法是反編譯類,添加一個實現Serializable,並重新編譯它,但如果它包含非序列化成員,事情會變得更加複雜。

0

另一種可能的解決方案可能是在Serializable類中定義一組使用第三方類實例的私有方法。這些特殊方法是序列化系統提供的特殊回調協議的一部分。這些方法將被調用在序列化/反序列化過程中。 他們的簽名必須是這樣的:

private void writeObject(ObjectOutputStream os) { 
// your code for saving the third party variables 
} 
private void readObject(ObjectInputStream is) { 
// your code to read the third party state, create a new ThirdParty instance, 
// and assign it to your class. 
} 

這個例子闡明瞭這個想法進一步:

public class MyClass implements Serializable 
{ 
    transient private ThirdParty thirdPartyInstance ; 
    private int myClassVariable ; 
    private void writeObject(ObjectOutputStream oos) 
    { 
     try 
     { 

      oos.defaultWriteObject(); 
      oos.writeInt(thirdPartyInstance.getThirdPartyVariable()); 
      oos.writeInt(thirdPartyInstance.getFourthPartyInstance().getFourthPartyVariable()); 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
    private void readObject(ObjectInputStream ois) 
    { 
     try 
     { 
      ois.defaultReadObject(); //the call to defaultReadObject method must always be before any other code in the try block 

      //Reconstructing thirdPartyInstance 
thirdPartyInstance =new ThirdParty(ois.readInt(),new FourthParty(ois.readInt())); 

     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
    MyClass(int myClassVariable, ThirdParty thirdPartyInstance) 
    { 
     this.myClassVariable=myClassVariable; 
     this.thirdPartyInstance=thirdPartyInstance; 
    } 
    ThirdParty getThirdPartyInstance() 
    { 
     return thirdPartyInstance; 
    } 

    int getMyClassVariable() 
    { 
     return myClassVariable; 
    } 

    public static void main(String args[]) 
    { 
     FourthParty fourthPartyInstance=new FourthParty(45); 
     ThirdParty thirdPartyInstance=new ThirdParty(13,fourthPartyInstance); 
     MyClass myClassInstance=new MyClass(7,thirdPartyInstance); 
     System.out.println("Before: ThirdParty variable value is "+myClassInstance.getThirdPartyInstance().getThirdPartyVariable()); 
     System.out.println("Before: FourthParty variable value is "+myClassInstance.getThirdPartyInstance().getFourthPartyInstance().getFourthPartyVariable()); 
     System.out.println("Before: MyClass variable value is "+myClassInstance.getMyClassVariable()); 
     try 
     {  
      FileOutputStream fios=new FileOutputStream("D://TestFileq.ser"); 
      ObjectOutputStream oos=new ObjectOutputStream(fios); 
      oos.writeObject(myClassInstance); 
      oos.close(); 


      FileInputStream fi = new FileInputStream("D://TestFileq.ser"); 
      ObjectInputStream objectIn = new ObjectInputStream(fi); 
      MyClass myClassInst = (MyClass)objectIn.readObject(); 
      System.out.println("After: ThirdParty variable value is "+myClassInst.getThirdPartyInstance().getThirdPartyVariable()); 
      System.out.println("After: FourthParty variable value is "+myClassInst.getThirdPartyInstance().getFourthPartyInstance().getFourthPartyVariable()); 
      System.out.println("After:MyClass variable value is "+myClassInst.getMyClassVariable()); 

     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 

    } 

} 
class ThirdParty 
{ 
    private int thirdPartyVariable; 
    private FourthParty fourthPartyInstance; 
    ThirdParty(int thirdPartyVariable,FourthParty fourthPartyInstance) 
    { 
     this.thirdPartyVariable=thirdPartyVariable; 
     this.fourthPartyInstance=fourthPartyInstance; 
    } 
    int getThirdPartyVariable() 
    { 
     return thirdPartyVariable; 
    } 
    FourthParty getFourthPartyInstance() 
    { 
     return fourthPartyInstance; 
    } 


} 
class FourthParty 
{ 
    private int fourthPartyVariable; 
    FourthParty(int fourthPartyVariable) 
    { 
     this.fourthPartyVariable=fourthPartyVariable; 
    } 
    int getFourthPartyVariable() 
    { 
     return fourthPartyVariable; 
    } 


} 

注意,MyClass中的thirdPartyInstance必須聲明瞬態否則類型的異常「java.io.NotSerializableException」發生。 欲瞭解更多解釋,請參閱: SCJP Java認證程序員,'Cathy Sierra',頁碼497

相關問題