【问题标题】:In java how do I serialize a class that is not marked Serializable?在 java 中,如何序列化未标记为 Serializable 的类?
【发布时间】:2011-01-08 00:34:24
【问题描述】:

我想序列化第三方库中的特定类。我该怎么做呢?

我假设我必须编写一个方法来接收类的对象并使用反射来获取私有成员值。然后对于反序列化,我将使用反射将值放回原处。

这行得通吗?有没有更简单的方法?

【问题讨论】:

  • 您是否需要它与未来版本兼容?
  • 不,它不需要与未来的版本兼容。
  • 您只是想保留数据吗?如果是这样,为什么不使用 JAXB?

标签: java reflection serialization


【解决方案1】:

您可以只使用实现 Serializable 的传输对象,并具有与第三方对象相同的字段。让传输对象实现一个返回原始第三方类对象的方法,就大功告成了:

伪代码:

class ThirdParty{

    int field1;
    int field2;
}

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 方法。

在这里查看一些序列化信息:

【讨论】:

  • 谢谢,这看起来不错,我该怎么处理私有成员变量?有没有简单的方法或者我需要反思?
  • 是的,反射是我所知道的访问不可见字段的唯一方法。 ://
  • “序列化秘密”链接已失效
  • 新链接:current, Wayback Machine
【解决方案2】:

你需要把它包装成可以进行序列化的东西。

理想情况下,第三方类支持某种其他形式的序列化,例如 XML 序列化(基于 bean 属性)。如果没有,你必须自己动手。这是否涉及反射或仅涉及 getter、setter 和构造函数取决于类。

在任何情况下,包装器都会将对象转换为 byte[] 或 String 或其他内容,并将其写入序列化输出。在反序列化时,它会根据该数据重建对象。

你的包装器必须实现的两种方法是

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

【讨论】:

    【解决方案3】:

    很大程度上取决于第三方类的性质。它是最终的,它是否有一个无参数的构造函数,你可以在给定已知值的情况下构造它还是由另一个类构造它,它本身是否包含不可序列化的成员?

    最简单的方法是反编译类,添加一个implements Serializable,然后重新编译它,但是如果它包含非Serializable成员,事情就变得更复杂了。

    【讨论】:

      【解决方案4】:

      另一种可能的解决方案是在您的 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 Sun 认证的 Java 6 程序员,'Cathy Sierra',页码 497

      【讨论】:

        猜你喜欢
        • 2015-02-15
        • 1970-01-01
        • 1970-01-01
        • 2011-12-06
        • 2016-04-30
        • 2016-07-23
        • 1970-01-01
        • 1970-01-01
        • 2015-09-27
        相关资源
        最近更新 更多