3

假设我有 A、B 和 C 类型的对象。我有 3 个地图,分别包含 A、B 和 C 的所有实例。在内部,A 和 B 都有 C 的 Maps。我希望能够随时存储和恢复应用程序的状态。

所以,直到今天我一直序列化类似金字塔的应用程序,我会在顶部对象上调用序列化,并且调用会传播到其他所有东西。我该如何处理这种情况?如果我在 A 地图上调用序列化,然后在 B 地图上调用,C 实例不会被保存两次吗?即使他们这样做了,当我在反序列化 A 映射后反序列化 B 映射时,反序列化是否会离开应用程序状态,因为它只是覆盖 C 实例?

提前致谢。

4

3 回答 3

8

Java 序列化机制知道对同一个对象的多个引用,并且不会复制它们。该对象将被存储一次,并且所有内部引用都将被保留。

反序列化后,您的对象将处于相同状态:只有一个实例和对该对象的多个引用。

于 2012-04-29T18:13:05.950 回答
4

ObjectOutputStream 的 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"
        }
    }
}
于 2012-04-29T18:17:54.270 回答
1

最好的办法是回到你的“金字塔状”模型,将你的地图存储在一个对象中,然后序列化这个对象;

public class ApplicationState implements Serializable {
    private Map<Foo, A> aMap;
    private Map<Bar, B> bMap;
}

序列化机制可以毫无问题地处理同一对象的图形和多个实例。

于 2012-04-29T18:14:22.103 回答