当前位置: 首页 > 知识库问答 >
问题:

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

汪飞捷
2023-03-14

外部化相对于序列化的主要优点是外部化仅保留对象的一部分,而不是序列化时保留整个对象。但我认为,如果我们不调用可序列化类的 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个答案

解晟睿
2023-03-14

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

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

< code>Serializable接口是一个标记接口,它向Java运行时环境发出信号,表明已经为实现类启用了基于Java的序列化。如果您不做任何其他事情,Java运行时会调用默认的序列化工具,该工具会从您的类的所有实例字段中为您创建一个序列化的表单。

类的最佳序列化形式是:

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

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

但是,如果 i 描述了有意义的状态,但 j 是一个实现细节,它不是对象逻辑状态的一部分,那么最佳做法是从流中删除 j 以获得更优化的序列化形式。

虽然默认的序列化形式(由内置的Java序列化工具发出)对于简单的值类来说通常是足够的,但是更复杂的抽象包含元数据和实现信息,它们不应该成为序列化形式的一部分。

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

  • 自定义序列化
  • 可外部化接口

前一种策略允许程序员通过使用瞬态关键字修改内置 Java 序列化工具的行为,并钩接到 readObject()、writeObject()、readResolve() 等方法中。 对于具有必须保护的不变量的不可变值类,特别建议使用序列化代理。

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

与序列化相比,外部化的主要好处是,外部化只持久化对象的一部分,而不是像序列化那样持久化整个对象

仅包含“对象的一部分”并且不包含重建对象在序列化之前存在的状态所需的所有信息的序列化形式是有缺陷的序列化形式。这种形式可能会在那些依赖序列化进行进程间通信的平台中引起问题。

 类似资料:
  • 问题内容: 确定,所以我编辑了问题,因为它不够清楚。 编辑2 :更新了JSON文件。 我在Android应用程序中使用GSON,我需要解析来自服务器的JSON文件,这些文件有点太复杂了。我不想让我的对象结构太沉重,所以我想简化内容: 所以我的对象的结构将不是JSON文件的结构。 例如,如果在JSON中,我有以下内容: 我不想保留我当前的对象结构,即一个对象,其中包含一个和一个“总计”。但是我只想将

  • 我想以 json 格式序列化一个自定义对象,其中 entryData 是我的域对象的列表。像这样: 下面是我在一次尝试中为获得json输出所做的工作: 但结果是entryData评估为字符串,引号转义: 我也尝试过这样做: 但是我得到了这个例外:

  • 我有下面的JSON,我正试图使用Jackson API反序列化它 我基本上需要一个附件类,它有一个AttachmentFile对象列表,如下所示: 如何使用自定义反序列化器实现这一点? 谢谢

  • 问题内容: 我有一个对象,其中包含一些要序列化的不可序列化字段。它们来自我无法更改的单独API,因此使它们可序列化不是一种选择。主要问题是Location类。它包含我需要的四个可以序列化的东西,所有整数。如何使用read / writeObject创建可以执行以下操作的自定义序列化方法: 我怎样才能做到这一点? 问题答案: Java支持自定义序列化。阅读“自定义默认协议”部分。 去引用: 但是,有

  • 我正在使用Spring Kafka集成,我有自己的值通用序列化器/反序列化器,如下所示 序列化程序: 反序列化程序: 序列化程序工作得很好,但是当涉及到在消费消息时反序列化值时,我得到了一个而不是所需的对象,请告诉我我错在哪里,提前感谢。

  • 如何基于json中指定的类类型,在Jackson中实现从json到Java对象的转换。 Java类型示例: