假设我有A,B和C类型的对象。我有3个地图,分别包含A,B和C的所有实例。在内部,A和B都有C的映射。我希望能够随时存储和恢复应用程序的状态。
所以,直到今天我总是序列化类似金字塔的应用程序,我将在顶部的Object上调用serialize,并且调用将传播到其他所有内容。我该如何处理这种情况?如果我在A地图上然后在B地图上调用序列化,那么C实例是否会被保存两次?即使它们这样做,反序列化是否会离开应用程序状态,因为在反序列化A映射后反序列化B映射时它只是覆盖C实例?
提前致谢。
答案 0 :(得分:4)
Java序列化机制知道对同一对象的多个引用,并且不会复制它们。该对象将被存储一次,并且将保留所有内部引用。
反序列化后,您的对象将处于相同的状态:只有一个实例和多个对该对象的引用。
答案 1 :(得分:3)
ObjectOutputStream writes的Javadoc:
writeObject方法用于将对象写入流。任何对象,包括字符串和数组,都是用writeObject编写的。可以将多个对象或基元写入流。必须从相应的ObjectInputstream中读取对象,这些对象具有与写入时相同的类型和顺序。
和
对其他对象的引用(瞬态或静态字段除外)也会导致写入这些对象。使用引用共享机制对对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。
特别是,如果将同一个对象重复写入ObjectOutputStream
,其数据只会写入一次。
您可以通过运行以下程序来验证这一点:
class A implements Serializable {
C c;
}
class B implements Serializable {
C c;
}
class C implements Serializable {
}
public class Test {
public static void main(String[] args) throws Exception {
C c = new C();
A a = new A();
a.c = c;
B b = new B();
b.c = c;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(a);
oos.writeObject(b);
oos.writeObject(c);
}
byte[] data = baos.toByteArray();
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
A newA = (A) ois.readObject();
B newB = (B) ois.readObject();
C newC = (C) ois.readObject();
System.out.println(newA.c == newC && newB.c == newC); // prints "true"
}
}
}
答案 2 :(得分:1)
最好的办法是回到你的“金字塔式”模型,将你的地图存储在一个对象中,然后序列化这个对象;
public class ApplicationState implements Serializable {
private Map<Foo, A> aMap;
private Map<Bar, B> bMap;
}
序列化机制可以毫无问题地处理同一对象的图形和多个实例。