繁体   English   中英

readObject/writeObject 在序列化中的使用

[英]Uses of readObject/writeObject in Serialization

我正在阅读这篇文章以了解更多关于 Java 序列化过程的信息。 当涉及到readObject/writeObject的使用时,我可以看到两个用例:

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

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

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


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

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

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

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

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

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

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();
    }

}

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

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

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

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();
    }

}

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

readObject的一个有趣用例是可序列化 Singleton 的实现,我们希望 Singleton 实例保留在序列化之前定义的字段值。 因此,在 Singleton 实例的反序列化期间,我们希望字段值与序列化之前完全相同,即使它们可以在序列化和反序列化之前更改。

@Serial
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
    boolean deserializedField = objectInputStream.readFields().get("field", isField());
    instance.setField(deserializedField);
}

@Serial
public Object readResolve() {
    return instance;
}

另外,我们在这里需要另一个有用的方法readResolve来始终返回对 singleton 实例的引用,而不是反序列化的 object。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM