【问题标题】:Uses of readObject/writeObject in Serialization序列化中 readObject/writeObject 的使用
【发布时间】:2011-08-20 04:32:36
【问题描述】:

我正在通过this article 了解更多关于Java 序列化过程的信息。谈到readObject/writeObject 的使用,我可以看到两个用例:

  1. 我们可以使用writeObject在字节码被序列化之前对其进行加密。从安全的角度来看,这是一件好事。
  2. 我们可以使用readObject 来执行任何需要在反序列化后立即执行的特定代码,当然从第 1 点开始,我们甚至可以使用readObject 来解密在序列化过程中被解密的字节码对象。

您在通过编写自定义 readObject/writeObject 方法对对象进行序列化/反序列化时遇到过其他实际情况吗?或者,如果您能指出我可以看到 readObject/writeObject 的一些体面和实际用途的任何地方?

【问题讨论】:

  • 请更新文章链接。

标签: java serialization


【解决方案1】:

使用自定义序列化可能有几个原因:

  1. 性能。
  2. 与外部系统的接口。 (超出您的范围,甚至是非 Java 系统。)
  3. 需要人类可读的格式。
  4. 支持旧版本的序列化类。

仅举几例,但我相信还有更多。

【讨论】:

    【解决方案2】:

    出于性能原因或向后兼容性原因,或者因为您要序列化的字段不可序列化,您可以实现自己的 readObject/writeObject。

    对于 readObject/writeObject 的好例子,我会查看 JDK 附带的源代码。或者我会尝试http://www.google.co.uk/search?q=readObject+writeObject+examples

    【讨论】:

      【解决方案3】:

      当您需要在对象被反序列化后初始化瞬态(非序列化)字段时,自定义 readObject 方法也很有用。


      顺便说一句,请查看Effective Java, Chapter 11(我不确定第二版中的章节/项目编号是什么。)。这是一本关于序列化的优秀读物。

      【讨论】:

      • 实际上确实如此...我正在寻找一些关于它在您的应用程序中的确切使用情况的 cmets。虽然自定义序列化是一个花哨的东西,但在 readObject() 中初始化瞬态或静态变量是经常使用的特性。
      • @Vicky:“实际上是这样”,Effective Java 链接回答了您的问题?
      • 是的,我现在正在看这本书。但是您关于初始化瞬态字段的回答对我有所帮助。
      【解决方案4】:

      使用基于 CipherOutputsStream 的 ObjectOutputStream 可以更好地进行解密。

      writeObject/readObject 最重要的用途是如果您想在多个代码修订版中保持序列化稳定。您的内部表示(成员变量)可能会发生变化,但序列化必须是稳定的,因为您与旧系统通信(例如,通过从文件中读取旧数据)。

      但对于这些情况,我更喜欢 Externalizable 接口,因为它更易于使用(没有只有 jvm 知道的隐式调用和方法)。

      【讨论】:

      【解决方案5】:
      public class Employee implements Serializable {
      
          private static final long serialVersionUID = 1L;
      
          private int empno;
          private String ename;
          private String job;
      
          // setter & getter
      
          @Override
          public String toString() {
              return "Employee [empno=" + empno + ", ename=" + ename + ", job=" + job
                      + "]";
          }
      
          private void writeObject(ObjectOutputStream out) throws IOException {
      
              // default serialization
              // out.defaultWriteObject();
      
              // custom serialization
              out.writeInt(empno);
              out.writeUTF(ename);
              // out.writeUTF(job); //job will not serialize
          }
      
          private void readObject(ObjectInputStream in) throws IOException,
                  ClassNotFoundException {
      
              // default deSerialization
              // in.defaultReadObject();
      
              // custom deSerialization
              empno = in.readInt();
              ename = in.readUTF();
              // this.job = in.readUTF();
          }
      
      }
      

      【讨论】:

        【解决方案6】:

        writeObject() 和 readObject() 方法也用于防止对象序列化。

        当一个 Super 类实现 Serializable 时,它​​的所有子类默认都是可序列化的。但是,如果您希望子类不可序列化,请覆盖子类中的 writeObject() 和 readObject() 方法,如下所示

        class Parent implements Serailizable
        {
            int id;
        
        } 
        
        class child extends Parent
        {
           String name;
        
           private void writeObject(ObjectOutputStream out) throws NotSerializableException
            {
                throw new NotSerializableException();
            }
            
            private void readObject(ObjectInputStream in) throws NotSerializableException
            {
                throw new NotSerializableException();
            }
        
        }
        

        现在子类的对象不能序列化了。

        【讨论】:

          猜你喜欢
          • 2015-08-18
          • 2019-01-29
          • 1970-01-01
          • 2013-01-22
          • 1970-01-01
          • 1970-01-01
          • 2018-01-05
          • 1970-01-01
          • 2015-01-09
          相关资源
          最近更新 更多