外部化相对于序列化的主要好处是,外部化仅保留对象的一部分,而不是像序列化那样保留整个对象。但我认为,如果我们不在 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
。
那么,我的假设是否正确,我们可以通过自定义序列化来模拟外部化概念?
最佳答案
So, is my assumption correct that we can simulate externalization concept via custom serialization ?
您的假设是正确的,程序员有能力为其选择的类构造任何序列化形式。
Serialized
接口(interface)是一个标记接口(interface),它向 Java 运行时环境发出信号,表明已为实现类启用基于 Java 的序列化。如果您不执行任何其他操作,Java 运行时将调用默认的序列化工具,该工具会根据类的所有实例字段为您创建序列化表单。
类的最佳序列化形式是:
- 仅描述其实例的逻辑状态
- 不包含特定于实现的详细信息或元数据
- 写入和读取流式传输和恢复类实例所需的最少信息
例如,在上面的代码中,如果 i
和 j
都描述了对象的有意义状态,则不包含 j 的序列化形式
会有缺陷,因为反序列化后您将无法将对象恢复到其有意义的状态。
但是,如果 i
描述有意义的状态,但 j
是不属于对象逻辑状态一部分的实现细节,那么最好的做法是消除 j
从流中获取更优化的序列化形式。
虽然默认的序列化形式(由内置的 Java 序列化工具发出)通常足以满足简单的值类,但更复杂的抽象包含元数据和实现信息,这些信息不应成为其序列化形式的一部分。
为了帮助程序员为其类设计最佳的序列化形式(如果默认形式不够用),Java 提供了两种广泛的机制来为对象生成最佳的序列化形式:
- 定制序列化
可外部化
接口(interface)
前一种策略允许程序员使用 transient
关键字修改内置 Java 序列化工具的行为,并 Hook 到 readObject()
等方法、writeObject()
、readResolve()
等。对于具有必须 protected 不变量的不可变值类,特别建议使用序列化代理。
后一种策略让程序员实现Externalized
而不是Serialized
(Externalizable
本身扩展了Serialized
)。与 Serialized
不同,Externalized
接口(interface)不是标记接口(interface)。它的方法在实现时旨在让程序员完全控制如何发出和恢复对象的序列化形式。
"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. "
仅包含“对象的一部分”并且不包含重构对象在序列化之前存在的状态所需的所有信息的序列化形式是有缺陷的序列化形式。这种形式可能会在那些依赖序列化进行进程间通信的平台中引起问题。
关于java - 通过自定义序列化模拟java对象外部化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37415777/