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

时间:2016-05-24 13:56:07

标签: java serialization java-custom-serialization

外部化优于序列化的主要好处是外部化只保留对象的一部分,而不是序列化的整个对象。但我认为如果我们不在 writeObject()方法中调用 ObjectOutputStream defaultWriteObject()方法,我们可以通过自定义序列化模拟外化。可序列化的类。因此,如果不调用 defaultWriteObject()方法并且只在 writeObject()方法中持久保存可序列化类所需的实例变量,我们就可以实现外部化的好处。

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

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

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

1 个答案:

答案 0 :(得分:0)

  

所以,我的假设是正确的,我们可以模拟外化   通过自定义序列化的概念?

你的假设是正确的,程序员有能力为他所选择的班级构建任何序列化的表格。

Serializable接口是标记接口,它向Java Runtime环境发出信号,表明已为实现类启用了基于Java的序列化。如果您不执行任何其他操作,Java Runtime将调用默认的序列化工具,该工具将从您的类的所有实例字段为您创建序列化表单。

一个类的最佳序列化形式是:

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

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

但是,如果i描述了有意义的状态,但j是一个不属于对象逻辑状态的实现细节,则最佳做法是消除{{1}从流中获取更优化的序列化表单。

虽然默认的序列化表单(由内置Java序列化工具发出)通常适用于简单的值类,但更复杂的抽象包含元数据和实现信息,这些信息不应成为其序列化表单的一部分。

为了帮助程序员为其类设计最佳的序列化表单(如果默认表单不合适),Java提供了两种广泛的机制来为对象生成最佳的序列化表单:

  • 自定义序列化
  • j界面

前一个策略允许程序员使用Externalizable关键字修改内置Java序列化工具的行为,并挂钩transientreadObject(),{等方法{1}}等。对于必须保护不变量的不可变值类,特别推荐使用序列化代理。

后一种策略有程序员实现writeObject()而不是readResolve()Externalizable本身扩展Serializable)。与Externalizable不同,Serializable界面不是标记界面。它的实现方法旨在让程序员完全控制对象的序列化表单的发射和恢复方式。

  

"外部化优于序列化的主要好处是外化只持有对象的一部分,而不是整个对象   在序列化的情况下。 "

一个序列化的表单,只包含"对象的一部分"并且它不包含重建对象状态所需的所有信息,因为它在序列化之前存在是一种有缺陷的序列化形式。这种形式可能会导致那些依赖序列化进行进程间通信的平台出现问题。