通过自定义序列化模拟 java 对象外部化

simulating java object externalization via custom serialization

外部化相对于序列化的主要好处是外部化只保留对象的一部分,而不是序列化情况下的整个对象。但我认为如果我们不调用 defaultWriteObject() 方法 ObjectOutputStream in writeObject( ) 可序列化的方法 class。因此,无需调用 defaultWriteObject() 方法,仅在 writeObject() 方法中保留可序列化 class 所需的实例变量,我们就可以实现外部化好处。

这是一个演示上述内容的示例:

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

那么,我的假设是否正确,即我们可以通过自定义序列化来模拟外部化概念?

So, is my assumption correct that we can simulate externalization concept via custom serialization ?

你的假设是正确的,程序员有能力为他选择的 class 构造任何序列化形式。

Serializable 接口是一个 标记接口,它向 Java 运行时环境发出信号,表示已启用基于 Java 的序列化实施 class。如果您什么都不做,Java 运行时会调用默认的序列化工具,它会从您的 class.

的所有实例字段中为您创建一个序列化表单。

class 的最佳序列化形式是:

  • 仅描述其实例的逻辑状态
  • 不包含特定于实现的详细信息或元数据
  • 写入和读取流式传输和恢复 class 个实例所需的最少信息

例如,在您上面的代码中,如果 ij 都描述了您的对象的有意义的状态,那么不包含 j 的序列化形式将是有缺陷的因为您将无法在反序列化后将对象恢复到其有意义的状态。

但是,如果 i 描述了有意义的状态,但 j 是一个不属于对象逻辑状态的实现细节,那么最好的做法是消除 j从流中获取更优化的序列化形式。

虽然默认序列化形式(由内置 Java 序列化工具发出)通常足以满足简单值 classes,但更复杂的抽象包含元数据和实施信息,不应成为他们的序列化形式的一部分。

为了帮助程序员为他们的 classes 设计最好的序列化形式(如果默认形式不够用),Java 提供了两种广泛的机制来为对象生成最佳序列化形式:

  • 自定义连载
  • Externalizable界面

前一种策略允许程序员通过使用 transient 关键字修改内置 Java 序列化工具的行为,并挂钩到 readObject()writeObject()readResolve() 等。对于具有必须保护的不变量的不可变值 classes,特别推荐使用序列化代理。

后一种策略让程序员实现 Externalizable 而不是 SerializableExternalizable 本身扩展了 Serializable)。与 Serializable 不同,Externalizable 接口不是标记接口。它的方法在实现时旨在让程序员完全控制对象的序列化形式的发出和恢复方式。

"The main benefit of externalization over serialization is that externalization persists only part of the object, not the whole object as in case of serialization. "

仅包含 "part of an object" 并且不包含重构对象在序列化之前存在的状态所需的所有信息的序列化形式是有缺陷的序列化形式。在那些依赖序列化进行进程间通信的平台中,这样的形式可以预料到会导致问题。